summaryrefslogtreecommitdiff
path: root/chromium/ui
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/ui
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
downloadqtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/ui')
-rw-r--r--chromium/ui/accelerated_widget_mac/accelerated_widget_mac.h1
-rw-r--r--chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm9
-rw-r--r--chromium/ui/accessibility/BUILD.gn17
-rw-r--r--chromium/ui/accessibility/DEPS7
-rw-r--r--chromium/ui/accessibility/PRESUBMIT.py4
-rw-r--r--chromium/ui/accessibility/ax_enum_util.cc16
-rw-r--r--chromium/ui/accessibility/ax_enums.mojom72
-rw-r--r--chromium/ui/accessibility/ax_event_generator.cc26
-rw-r--r--chromium/ui/accessibility/ax_event_generator_unittest.cc15
-rw-r--r--chromium/ui/accessibility/ax_node_data.cc7
-rw-r--r--chromium/ui/accessibility/ax_position.h8
-rw-r--r--chromium/ui/accessibility/ax_tree.cc6
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer.h17
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc1
-rw-r--r--chromium/ui/accessibility/mojom/BUILD.gn20
-rw-r--r--chromium/ui/accessibility/mojom/OWNERS6
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data.mojom30
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data.typemap19
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc160
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h50
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc134
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data.mojom27
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data.typemap15
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.cc36
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.h55
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc50
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update.mojom18
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update.typemap15
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc23
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h36
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc31
-rw-r--r--chromium/ui/accessibility/mojom/typemaps.gni9
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.cc18
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.h6
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc5
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.h2
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_mac.mm8
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_unittest.cc5
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc95
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.h2
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc134
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_relation_win.cc5
-rw-r--r--chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc1
-rw-r--r--chromium/ui/accessibility/run_all_unittests.cc18
-rw-r--r--chromium/ui/android/BUILD.gn15
-rw-r--r--chromium/ui/android/DEPS2
-rw-r--r--chromium/ui/android/delegated_frame_host_android.cc70
-rw-r--r--chromium/ui/android/delegated_frame_host_android.h7
-rw-r--r--chromium/ui/android/delegated_frame_host_android_unittest.cc167
-rw-r--r--chromium/ui/android/event_forwarder.cc58
-rw-r--r--chromium/ui/android/event_forwarder.h35
-rw-r--r--chromium/ui/android/resources/nine_patch_resource.cc1
-rw-r--r--chromium/ui/android/resources/resource.cc1
-rw-r--r--chromium/ui/android/resources/resource_manager_impl_unittest.cc1
-rw-r--r--chromium/ui/android/view_android.cc19
-rw-r--r--chromium/ui/android/view_android.h5
-rw-r--r--chromium/ui/android/window_android.cc16
-rw-r--r--chromium/ui/android/window_android.h7
-rw-r--r--chromium/ui/android/window_android_compositor.h9
-rw-r--r--chromium/ui/app_list/BUILD.gn38
-rw-r--r--chromium/ui/app_list/presenter/BUILD.gn114
-rw-r--r--chromium/ui/app_list/presenter/app_list_presenter.mojom71
-rw-r--r--chromium/ui/app_list/vector_icons/BUILD.gn15
-rw-r--r--chromium/ui/arc/BUILD.gn18
-rw-r--r--chromium/ui/arc/OWNERS4
-rw-r--r--chromium/ui/arc/notification/arc_notification_content_view.cc233
-rw-r--r--chromium/ui/arc/notification/arc_notification_content_view.h27
-rw-r--r--chromium/ui/arc/notification/arc_notification_content_view_delegate.h30
-rw-r--r--chromium/ui/arc/notification/arc_notification_content_view_unittest.cc142
-rw-r--r--chromium/ui/arc/notification/arc_notification_delegate.cc11
-rw-r--r--chromium/ui/arc/notification/arc_notification_delegate.h3
-rw-r--r--chromium/ui/arc/notification/arc_notification_item.h14
-rw-r--r--chromium/ui/arc/notification/arc_notification_item_impl.cc39
-rw-r--r--chromium/ui/arc/notification/arc_notification_item_impl.h10
-rw-r--r--chromium/ui/arc/notification/arc_notification_manager.cc33
-rw-r--r--chromium/ui/arc/notification/arc_notification_manager.h16
-rw-r--r--chromium/ui/arc/notification/arc_notification_manager_unittest.cc2
-rw-r--r--chromium/ui/arc/notification/arc_notification_surface_manager_impl.cc1
-rw-r--r--chromium/ui/arc/notification/arc_notification_view.cc129
-rw-r--r--chromium/ui/arc/notification/arc_notification_view.h17
-rw-r--r--chromium/ui/arc/notification/arc_notification_view_unittest.cc173
-rw-r--r--chromium/ui/arc/notification/mock_arc_notification_item.cc85
-rw-r--r--chromium/ui/arc/notification/mock_arc_notification_item.h70
-rw-r--r--chromium/ui/aura/BUILD.gn16
-rw-r--r--chromium/ui/aura/OWNERS4
-rw-r--r--chromium/ui/aura/client/aura_constants.cc2
-rw-r--r--chromium/ui/aura/client/aura_constants.h6
-rw-r--r--chromium/ui/aura/env.cc14
-rw-r--r--chromium/ui/aura/env.h13
-rw-r--r--chromium/ui/aura/event_injector.cc8
-rw-r--r--chromium/ui/aura/event_injector.h4
-rw-r--r--chromium/ui/aura/gestures/gesture_recognizer_unittest.cc1
-rw-r--r--chromium/ui/aura/hit_test_data_provider_aura.cc7
-rw-r--r--chromium/ui/aura/hit_test_data_provider_aura_unittest.cc22
-rw-r--r--chromium/ui/aura/local/window_port_local.cc13
-rw-r--r--chromium/ui/aura/local/window_port_local.h3
-rw-r--r--chromium/ui/aura/mus/client_surface_embedder.cc4
-rw-r--r--chromium/ui/aura/mus/drag_drop_controller_mus.cc1
-rw-r--r--chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc1
-rw-r--r--chromium/ui/aura/mus/embed_root.cc133
-rw-r--r--chromium/ui/aura/mus/embed_root.h80
-rw-r--r--chromium/ui/aura/mus/embed_root_delegate.h41
-rw-r--r--chromium/ui/aura/mus/focus_synchronizer.h2
-rw-r--r--chromium/ui/aura/mus/input_method_mus.cc39
-rw-r--r--chromium/ui/aura/mus/input_method_mus.h14
-rw-r--r--chromium/ui/aura/mus/input_method_mus_unittest.cc19
-rw-r--r--chromium/ui/aura/mus/mus_context_factory.cc1
-rw-r--r--chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc1
-rw-r--r--chromium/ui/aura/mus/platform_event_source_mus_ozone.cc26
-rw-r--r--chromium/ui/aura/mus/platform_event_source_mus_ozone.h35
-rw-r--r--chromium/ui/aura/mus/property_converter.cc1
-rw-r--r--chromium/ui/aura/mus/user_activity_forwarder_unittest.cc1
-rw-r--r--chromium/ui/aura/mus/window_port_mus.cc30
-rw-r--r--chromium/ui/aura/mus/window_port_mus.h8
-rw-r--r--chromium/ui/aura/mus/window_tree_client.cc464
-rw-r--r--chromium/ui/aura/mus/window_tree_client.h118
-rw-r--r--chromium/ui/aura/mus/window_tree_client_unittest.cc112
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus.cc3
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus_unittest.cc1
-rw-r--r--chromium/ui/aura/scoped_keyboard_hook.cc6
-rw-r--r--chromium/ui/aura/scoped_keyboard_hook.h8
-rw-r--r--chromium/ui/aura/test/ui_controls_factory_ozone.cc176
-rw-r--r--chromium/ui/aura/window.cc27
-rw-r--r--chromium/ui/aura/window.h18
-rw-r--r--chromium/ui/aura/window_event_dispatcher.cc7
-rw-r--r--chromium/ui/aura/window_event_dispatcher_unittest.cc18
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.cc24
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.h13
-rw-r--r--chromium/ui/aura/window_occlusion_tracker_unittest.cc110
-rw-r--r--chromium/ui/aura/window_port.h13
-rw-r--r--chromium/ui/aura/window_port_for_shutdown.cc10
-rw-r--r--chromium/ui/aura/window_port_for_shutdown.h3
-rw-r--r--chromium/ui/aura/window_targeter.cc28
-rw-r--r--chromium/ui/aura/window_targeter.h11
-rw-r--r--chromium/ui/aura/window_tree_host.cc70
-rw-r--r--chromium/ui/aura/window_tree_host.h47
-rw-r--r--chromium/ui/aura/window_tree_host_platform.cc45
-rw-r--r--chromium/ui/aura/window_tree_host_platform.h8
-rw-r--r--chromium/ui/aura/window_tree_host_unittest.cc8
-rw-r--r--chromium/ui/base/BUILD.gn18
-rw-r--r--chromium/ui/base/accelerators/accelerator.cc285
-rw-r--r--chromium/ui/base/accelerators/accelerator.h18
-rw-r--r--chromium/ui/base/accelerators/accelerator_unittest.cc47
-rw-r--r--chromium/ui/base/accelerators/mojo/BUILD.gn2
-rw-r--r--chromium/ui/base/accelerators/mojo/DEPS4
-rw-r--r--chromium/ui/base/accelerators/mojo/accelerator.mojom2
-rw-r--r--chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h10
-rw-r--r--chromium/ui/base/accelerators/mojo/accelerator_struct_traits_unittest.cc6
-rw-r--r--chromium/ui/base/base_window.h3
-rw-r--r--chromium/ui/base/class_property_unittest.cc1
-rw-r--r--chromium/ui/base/clipboard/clipboard_aurax11.cc12
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac_unittest.mm14
-rw-r--r--chromium/ui/base/cocoa/fullscreen_window_manager.h40
-rw-r--r--chromium/ui/base/cocoa/fullscreen_window_manager.mm116
-rw-r--r--chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm32
-rw-r--r--chromium/ui/base/cocoa/menu_controller.mm1
-rw-r--r--chromium/ui/base/cocoa/secure_password_input.h29
-rw-r--r--chromium/ui/base/cocoa/secure_password_input.mm63
-rw-r--r--chromium/ui/base/cocoa/text_services_context_menu.cc21
-rw-r--r--chromium/ui/base/cocoa/text_services_context_menu.h5
-rw-r--r--chromium/ui/base/cursor/cursor_loader_ozone.cc16
-rw-r--r--chromium/ui/base/cursor/cursor_loader_ozone.h3
-rw-r--r--chromium/ui/base/cursor/cursor_loader_x11.h7
-rw-r--r--chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h4
-rw-r--r--chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h3
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h4
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_builder_mac.mm1
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc1
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc1
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_unittest.cc2
-rw-r--r--chromium/ui/base/ime/BUILD.gn44
-rw-r--r--chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn11
-rw-r--r--chromium/ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom15
-rw-r--r--chromium/ui/base/ime/composition_text_unittest.cc14
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango.cc15
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango_unittest.cc56
-rw-r--r--chromium/ui/base/ime/dummy_input_method.cc5
-rw-r--r--chromium/ui/base/ime/dummy_input_method.h7
-rw-r--r--chromium/ui/base/ime/ime_engine_handler_interface.h4
-rw-r--r--chromium/ui/base/ime/ime_text_span.cc14
-rw-r--r--chromium/ui/base/ime/ime_text_span.h18
-rw-r--r--chromium/ui/base/ime/input_method.h7
-rw-r--r--chromium/ui/base/ime/input_method_auralinux.cc21
-rw-r--r--chromium/ui/base/ime/input_method_auralinux.h2
-rw-r--r--chromium/ui/base/ime/input_method_base.cc23
-rw-r--r--chromium/ui/base/ime/input_method_base.h12
-rw-r--r--chromium/ui/base/ime/input_method_base_unittest.cc5
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.cc99
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.h26
-rw-r--r--chromium/ui/base/ime/input_method_chromeos_unittest.cc162
-rw-r--r--chromium/ui/base/ime/input_method_factory.cc4
-rw-r--r--chromium/ui/base/ime/input_method_initializer.cc14
-rw-r--r--chromium/ui/base/ime/input_method_mac.h2
-rw-r--r--chromium/ui/base/ime/input_method_mac.mm5
-rw-r--r--chromium/ui/base/ime/input_method_minimal.cc6
-rw-r--r--chromium/ui/base/ime/input_method_minimal.h2
-rw-r--r--chromium/ui/base/ime/input_method_win.cc256
-rw-r--r--chromium/ui/base/ime/input_method_win.h39
-rw-r--r--chromium/ui/base/ime/input_method_win_base.cc276
-rw-r--r--chromium/ui/base/ime/input_method_win_base.h67
-rw-r--r--chromium/ui/base/ime/input_method_win_tsf.cc147
-rw-r--r--chromium/ui/base/ime/input_method_win_tsf.h58
-rw-r--r--chromium/ui/base/ime/linux/fake_input_method_context_factory.cc1
-rw-r--r--chromium/ui/base/ime/mock_input_method.cc5
-rw-r--r--chromium/ui/base/ime/mock_input_method.h7
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.cc12
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.cc70
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.h99
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.cc30
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.h35
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc (renamed from chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc)143
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h51
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc (renamed from chromium/ui/base/win/osk_display_manager_unittest.cc)21
-rw-r--r--chromium/ui/base/ime/win/osk_display_manager.cc31
-rw-r--r--chromium/ui/base/ime/win/osk_display_manager.h (renamed from chromium/ui/base/win/osk_display_manager.h)35
-rw-r--r--chromium/ui/base/ime/win/osk_display_observer.h (renamed from chromium/ui/base/win/osk_display_observer.h)15
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc542
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.h94
-rw-r--r--chromium/ui/base/ime/win/tsf_event_router.cc296
-rw-r--r--chromium/ui/base/ime/win/tsf_event_router.h78
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc925
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.h311
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc1302
-rw-r--r--chromium/ui/base/l10n/l10n_util_unittest.cc1
-rw-r--r--chromium/ui/base/material_design/material_design_controller.cc95
-rw-r--r--chromium/ui/base/material_design/material_design_controller.h9
-rw-r--r--chromium/ui/base/models/list_model.h1
-rw-r--r--chromium/ui/base/models/list_model_unittest.cc1
-rw-r--r--chromium/ui/base/models/simple_menu_model.cc18
-rw-r--r--chromium/ui/base/models/simple_menu_model.h6
-rw-r--r--chromium/ui/base/models/tree_node_iterator_unittest.cc1
-rw-r--r--chromium/ui/base/models/tree_node_model_unittest.cc1
-rw-r--r--chromium/ui/base/mojo/DEPS2
-rw-r--r--chromium/ui/base/mojo/clipboard.typemap2
-rw-r--r--chromium/ui/base/mojo/clipboard_struct_traits.h2
-rw-r--r--chromium/ui/base/nine_image_painter_factory.cc1
-rw-r--r--chromium/ui/base/resource/data_pack.cc1
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc7
-rw-r--r--chromium/ui/base/resource/resource_bundle_android.cc1
-rw-r--r--chromium/ui/base/resource/resource_bundle_win.cc1
-rw-r--r--chromium/ui/base/ui_base_features.cc48
-rw-r--r--chromium/ui/base/ui_base_features.h22
-rw-r--r--chromium/ui/base/ui_base_switches.cc13
-rw-r--r--chromium/ui/base/ui_base_switches.h4
-rw-r--r--chromium/ui/base/ui_features.gni7
-rw-r--r--chromium/ui/base/user_activity/user_activity_detector.cc8
-rw-r--r--chromium/ui/base/user_activity/user_activity_detector.h4
-rw-r--r--chromium/ui/base/user_activity/user_activity_detector_unittest.cc2
-rw-r--r--chromium/ui/base/win/direct_manipulation.cc476
-rw-r--r--chromium/ui/base/win/direct_manipulation.h161
-rw-r--r--chromium/ui/base/win/direct_manipulation_unittest.cc756
-rw-r--r--chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h60
-rw-r--r--chromium/ui/base/win/osk_display_manager.cc379
-rw-r--r--chromium/ui/base/win/shell.cc7
-rw-r--r--chromium/ui/base/win/shell.h11
-rw-r--r--chromium/ui/base/win/window_event_target.h30
-rw-r--r--chromium/ui/base/x/selection_owner.cc1
-rw-r--r--chromium/ui/base/x/selection_requestor.h2
-rw-r--r--chromium/ui/base/x/selection_requestor_unittest.cc14
-rw-r--r--chromium/ui/base/x/x11_util.cc2
-rw-r--r--chromium/ui/base/x/x11_util.h2
-rw-r--r--chromium/ui/chromeos/BUILD.gn2
-rw-r--r--chromium/ui/compositor/BUILD.gn2
-rw-r--r--chromium/ui/compositor/OWNERS2
-rw-r--r--chromium/ui/compositor/callback_layer_animation_observer_unittest.cc1
-rw-r--r--chromium/ui/compositor/compositor.cc6
-rw-r--r--chromium/ui/compositor/compositor.h1
-rw-r--r--chromium/ui/compositor/layer.cc36
-rw-r--r--chromium/ui/compositor/layer.h17
-rw-r--r--chromium/ui/compositor/layer_animation_element.cc1
-rw-r--r--chromium/ui/compositor/layer_animator_unittest.cc1
-rw-r--r--chromium/ui/compositor/layer_delegate.cc3
-rw-r--r--chromium/ui/compositor/layer_delegate.h4
-rw-r--r--chromium/ui/compositor/layer_owner.cc1
-rw-r--r--chromium/ui/compositor/layer_owner_unittest.cc1
-rw-r--r--chromium/ui/compositor/layer_unittest.cc172
-rw-r--r--chromium/ui/compositor/run_all_unittests.cc5
-rw-r--r--chromium/ui/compositor_extra/BUILD.gn18
-rw-r--r--chromium/ui/compositor_extra/DEPS5
-rw-r--r--chromium/ui/compositor_extra/shadow.cc (renamed from chromium/ui/wm/core/shadow.cc)6
-rw-r--r--chromium/ui/compositor_extra/shadow.h (renamed from chromium/ui/wm/core/shadow.h)14
-rw-r--r--chromium/ui/compositor_extra/shadow_unittest.cc (renamed from chromium/ui/wm/core/shadow_unittest.cc)34
-rw-r--r--chromium/ui/content_accelerators/BUILD.gn2
-rw-r--r--chromium/ui/content_accelerators/DEPS2
-rw-r--r--chromium/ui/content_accelerators/accelerator_util.cc2
-rw-r--r--chromium/ui/display/BUILD.gn3
-rw-r--r--chromium/ui/display/OWNERS5
-rw-r--r--chromium/ui/display/display.cc2
-rw-r--r--chromium/ui/display/display.h4
-rw-r--r--chromium/ui/display/display_layout.cc110
-rw-r--r--chromium/ui/display/display_layout.h10
-rw-r--r--chromium/ui/display/display_switches.cc21
-rw-r--r--chromium/ui/display/display_switches.h5
-rw-r--r--chromium/ui/display/mac/screen_mac.mm2
-rw-r--r--chromium/ui/display/manager/BUILD.gn2
-rw-r--r--chromium/ui/display/manager/chromeos/DEPS1
-rw-r--r--chromium/ui/display/manager/chromeos/display_change_observer.cc78
-rw-r--r--chromium/ui/display/manager/chromeos/display_change_observer.h2
-rw-r--r--chromium/ui/display/manager/chromeos/display_change_observer_unittest.cc36
-rw-r--r--chromium/ui/display/manager/chromeos/display_configurator.cc92
-rw-r--r--chromium/ui/display/manager/chromeos/display_configurator.h20
-rw-r--r--chromium/ui/display/manager/chromeos/display_configurator_unittest.cc30
-rw-r--r--chromium/ui/display/manager/chromeos/display_util.cc76
-rw-r--r--chromium/ui/display/manager/chromeos/display_util.h5
-rw-r--r--chromium/ui/display/manager/chromeos/display_utils_unittest.cc111
-rw-r--r--chromium/ui/display/manager/chromeos/touch_device_manager.cc109
-rw-r--r--chromium/ui/display/manager/chromeos/touch_device_manager.h70
-rw-r--r--chromium/ui/display/manager/chromeos/touch_device_manager_unittest.cc264
-rw-r--r--chromium/ui/display/manager/chromeos/touch_transform_controller_unittest.cc1
-rw-r--r--chromium/ui/display/manager/chromeos/update_display_configuration_task_unittest.cc1
-rw-r--r--chromium/ui/display/manager/display_manager.cc91
-rw-r--r--chromium/ui/display/manager/display_manager.h13
-rw-r--r--chromium/ui/display/manager/display_pref_util.h64
-rw-r--r--chromium/ui/display/manager/fake_display_delegate.cc1
-rw-r--r--chromium/ui/display/manager/fake_display_snapshot.cc12
-rw-r--r--chromium/ui/display/manager/fake_display_snapshot.h6
-rw-r--r--chromium/ui/display/manager/json_converter.cc1
-rw-r--r--chromium/ui/display/manager/managed_display_info.cc20
-rw-r--r--chromium/ui/display/manager/managed_display_info.h20
-rw-r--r--chromium/ui/display/mojo/BUILD.gn2
-rw-r--r--chromium/ui/display/mojo/display_snapshot.mojom8
-rw-r--r--chromium/ui/display/mojo/display_snapshot_struct_traits.cc2
-rw-r--r--chromium/ui/display/mojo/display_snapshot_struct_traits.h9
-rw-r--r--chromium/ui/display/mojo/display_struct_traits_unittest.cc22
-rw-r--r--chromium/ui/display/types/display_constants.h3
-rw-r--r--chromium/ui/display/types/display_snapshot.cc15
-rw-r--r--chromium/ui/display/types/display_snapshot.h19
-rw-r--r--chromium/ui/display/util/OWNERS4
-rw-r--r--chromium/ui/display/util/edid_parser.cc489
-rw-r--r--chromium/ui/display/util/edid_parser.h107
-rw-r--r--chromium/ui/display/util/edid_parser_fuzzer.cc12
-rw-r--r--chromium/ui/display/util/edid_parser_unittest.cc427
-rw-r--r--chromium/ui/display/util/fuzz_corpus/evebin0 -> 128 bytes
-rw-r--r--chromium/ui/display/util/fuzz_corpus/hpz32xbin0 -> 256 bytes
-rw-r--r--chromium/ui/display/util/x11/edid_parser_x11.cc23
-rw-r--r--chromium/ui/display/util/x11/edid_parser_x11.h14
-rw-r--r--chromium/ui/events/BUILD.gn15
-rw-r--r--chromium/ui/events/base_event_utils.cc4
-rw-r--r--chromium/ui/events/base_event_utils.h2
-rw-r--r--chromium/ui/events/blink/BUILD.gn6
-rw-r--r--chromium/ui/events/blink/DEPS22
-rw-r--r--chromium/ui/events/blink/blink_event_util.cc97
-rw-r--r--chromium/ui/events/blink/blink_event_util.h6
-rw-r--r--chromium/ui/events/blink/blink_event_util_unittest.cc6
-rw-r--r--chromium/ui/events/blink/compositor_thread_event_queue.cc1
-rw-r--r--chromium/ui/events/blink/event_with_callback.cc1
-rw-r--r--chromium/ui/events/blink/fling_booster.cc4
-rw-r--r--chromium/ui/events/blink/fling_booster.h2
-rw-r--r--chromium/ui/events/blink/fling_booster_unittest.cc10
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.cc162
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.h29
-rw-r--r--chromium/ui/events/blink/input_handler_proxy_client.h2
-rw-r--r--chromium/ui/events/blink/input_handler_proxy_unittest.cc1541
-rw-r--r--chromium/ui/events/blink/input_scroll_elasticity_controller.h4
-rw-r--r--chromium/ui/events/blink/input_scroll_elasticity_controller_unittest.cc16
-rw-r--r--chromium/ui/events/blink/snap_fling_controller.cc102
-rw-r--r--chromium/ui/events/blink/snap_fling_controller.h96
-rw-r--r--chromium/ui/events/blink/snap_fling_controller_unittest.cc167
-rw-r--r--chromium/ui/events/blink/snap_fling_curve.cc119
-rw-r--r--chromium/ui/events/blink/snap_fling_curve.h77
-rw-r--r--chromium/ui/events/blink/snap_fling_curve_unittest.cc71
-rw-r--r--chromium/ui/events/blink/web_input_event.cc74
-rw-r--r--chromium/ui/events/blink/web_input_event.h10
-rw-r--r--chromium/ui/events/blink/web_input_event_builders_win.h6
-rw-r--r--chromium/ui/events/blink/web_input_event_builders_win_unittest.cc4
-rw-r--r--chromium/ui/events/blink/web_input_event_traits.cc30
-rw-r--r--chromium/ui/events/blink/web_input_event_traits.h2
-rw-r--r--chromium/ui/events/blink/web_input_event_traits_unittest.cc13
-rw-r--r--chromium/ui/events/chromecast/OWNERS4
-rw-r--r--chromium/ui/events/chromecast/scroller.cc2
-rw-r--r--chromium/ui/events/cocoa/events_mac.mm46
-rw-r--r--chromium/ui/events/devices/BUILD.gn1
-rw-r--r--chromium/ui/events/devices/input_device.cc2
-rw-r--r--chromium/ui/events/devices/input_device.h7
-rw-r--r--chromium/ui/events/devices/x11/device_data_manager_x11.h2
-rw-r--r--chromium/ui/events/event.cc73
-rw-r--r--chromium/ui/events/event.h51
-rw-r--r--chromium/ui/events/event_constants.h31
-rw-r--r--chromium/ui/events/event_rewriter_unittest.cc58
-rw-r--r--chromium/ui/events/event_source.cc24
-rw-r--r--chromium/ui/events/event_target.cc53
-rw-r--r--chromium/ui/events/event_target.h39
-rw-r--r--chromium/ui/events/event_target_unittest.cc104
-rw-r--r--chromium/ui/events/event_unittest.cc179
-rw-r--r--chromium/ui/events/event_utils.cc4
-rw-r--r--chromium/ui/events/event_utils.h52
-rw-r--r--chromium/ui/events/events_default.cc40
-rw-r--r--chromium/ui/events/events_stub.cc50
-rw-r--r--chromium/ui/events/gestures/blink/BUILD.gn2
-rw-r--r--chromium/ui/events/gestures/blink/DEPS8
-rw-r--r--chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc5
-rw-r--r--chromium/ui/events/gestures/blink/web_gesture_curve_impl.h4
-rw-r--r--chromium/ui/events/gestures/blink/web_gesture_curve_impl_unittest.cc6
-rw-r--r--chromium/ui/events/keyboard_hook.h3
-rw-r--r--chromium/ui/events/keyboard_hook_base.cc4
-rw-r--r--chromium/ui/events/keyboard_hook_base.h3
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_x.cc611
-rw-r--r--chromium/ui/events/keycodes/platform_key_map_win.cc2
-rw-r--r--chromium/ui/events/keycodes/platform_key_map_win.h2
-rw-r--r--chromium/ui/events/mojo/BUILD.gn2
-rw-r--r--chromium/ui/events/mojo/event.mojom26
-rw-r--r--chromium/ui/events/mojo/event.typemap7
-rw-r--r--chromium/ui/events/mojo/event_constants.mojom22
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.cc56
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.h84
-rw-r--r--chromium/ui/events/mojo/struct_traits_unittest.cc57
-rw-r--r--chromium/ui/events/ozone/device/device_manager.cc1
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.cc14
-rw-r--r--chromium/ui/events/ozone/device/udev/device_manager_udev.cc1
-rw-r--r--chromium/ui/events/ozone/device/udev/device_manager_udev.h8
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev.cc2
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev.h7
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev_impl.h2
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_test_util.cc4
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.cc11
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.h5
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory_evdev.cc79
-rw-r--r--chromium/ui/events/ozone/evdev/event_thread_evdev.cc2
-rw-r--r--chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/input_controller_evdev.cc5
-rw-r--r--chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc4
-rw-r--r--chromium/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc27
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc8
-rw-r--r--chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.h2
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc1
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h2
-rw-r--r--chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder.cc1
-rw-r--r--chromium/ui/events/ozone/events_ozone.cc33
-rw-r--r--chromium/ui/events/ozone/events_ozone.h4
-rw-r--r--chromium/ui/events/ozone/gamepad/gamepad_mapping.cc1
-rw-r--r--chromium/ui/events/ozone/gamepad/generic_gamepad_mapping.cc1
-rw-r--r--chromium/ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc1
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc1
-rw-r--r--chromium/ui/events/platform/BUILD.gn2
-rw-r--r--chromium/ui/events/platform/platform_event_dispatcher.h2
-rw-r--r--chromium/ui/events/platform/platform_event_observer.h2
-rw-r--r--chromium/ui/events/platform/platform_event_source.cc1
-rw-r--r--chromium/ui/events/platform/platform_event_source.h4
-rw-r--r--chromium/ui/events/platform/platform_event_source_unittest.cc35
-rw-r--r--chromium/ui/events/platform/platform_event_types.h14
-rw-r--r--chromium/ui/events/platform/x11/BUILD.gn4
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.cc2
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.h3
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source_glib.cc1
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source_libevent.cc11
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source_libevent.h6
-rw-r--r--chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc45
-rw-r--r--chromium/ui/events/platform_event.h43
-rw-r--r--chromium/ui/events/system_input_injector.cc1
-rw-r--r--chromium/ui/events/win/events_win.cc59
-rw-r--r--chromium/ui/events/win/keyboard_hook_win.cc2
-rw-r--r--chromium/ui/events/x/events_x.cc40
-rw-r--r--chromium/ui/events/x/events_x_unittest.cc3
-rw-r--r--chromium/ui/file_manager/file_manager/background/js/compiled_resources2.gyp18
-rw-r--r--chromium/ui/file_manager/file_manager/common/js/compiled_resources2.gyp8
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/ui/compiled_resources2.gyp2
-rw-r--r--chromium/ui/file_manager/file_manager/test/BUILD.gn13
-rw-r--r--chromium/ui/gfx/BUILD.gn15
-rw-r--r--chromium/ui/gfx/DEPS2
-rw-r--r--chromium/ui/gfx/OWNERS3
-rw-r--r--chromium/ui/gfx/animation/animation.cc1
-rw-r--r--chromium/ui/gfx/animation/animation_test_api.cc1
-rw-r--r--chromium/ui/gfx/break_list.h2
-rw-r--r--chromium/ui/gfx/client_native_pixmap_factory.cc24
-rw-r--r--chromium/ui/gfx/client_native_pixmap_factory.h4
-rw-r--r--chromium/ui/gfx/color_palette.h11
-rw-r--r--chromium/ui/gfx/color_space.cc73
-rw-r--r--chromium/ui/gfx/color_space.h8
-rw-r--r--chromium/ui/gfx/color_space_unittest.cc7
-rw-r--r--chromium/ui/gfx/color_space_win.cc1
-rw-r--r--chromium/ui/gfx/color_transform.cc56
-rw-r--r--chromium/ui/gfx/color_transform_unittest.cc87
-rw-r--r--chromium/ui/gfx/color_utils.cc12
-rw-r--r--chromium/ui/gfx/decorated_text_mac.h22
-rw-r--r--chromium/ui/gfx/decorated_text_mac.mm51
-rw-r--r--chromium/ui/gfx/font_list_unittest.cc7
-rw-r--r--chromium/ui/gfx/font_names_testing.cc8
-rw-r--r--chromium/ui/gfx/font_names_testing.h1
-rw-r--r--chromium/ui/gfx/font_render_params.h2
-rw-r--r--chromium/ui/gfx/font_render_params_linux_unittest.cc161
-rw-r--r--chromium/ui/gfx/font_unittest.cc31
-rw-r--r--chromium/ui/gfx/gpu_fence_handle.h1
-rw-r--r--chromium/ui/gfx/image/canvas_image_source.cc42
-rw-r--r--chromium/ui/gfx/image/canvas_image_source.h33
-rw-r--r--chromium/ui/gfx/image/mojo/image_traits_unittest.cc1
-rw-r--r--chromium/ui/gfx/interpolated_transform.cc1
-rw-r--r--chromium/ui/gfx/interpolated_transform_unittest.cc1
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc4
-rw-r--r--chromium/ui/gfx/linux/native_pixmap_dmabuf.cc3
-rw-r--r--chromium/ui/gfx/linux/native_pixmap_dmabuf.h3
-rw-r--r--chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h25
-rw-r--r--chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm32
-rw-r--r--chromium/ui/gfx/native_pixmap.h5
-rw-r--r--chromium/ui/gfx/paint_vector_icon.cc50
-rw-r--r--chromium/ui/gfx/paint_vector_icon_unittest.cc38
-rw-r--r--chromium/ui/gfx/platform_font_linux_unittest.cc18
-rw-r--r--chromium/ui/gfx/render_text.cc35
-rw-r--r--chromium/ui/gfx/render_text.h30
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc7
-rw-r--r--chromium/ui/gfx/render_text_mac.mm3
-rw-r--r--chromium/ui/gfx/render_text_test_api.h9
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc314
-rw-r--r--chromium/ui/gfx/skia_paint_util.cc10
-rw-r--r--chromium/ui/gfx/skia_util.cc5
-rw-r--r--chromium/ui/gfx/skia_util.h1
-rw-r--r--chromium/ui/gfx/vector_icon_types.h28
-rw-r--r--chromium/ui/gfx/x/x11.h1
-rw-r--r--chromium/ui/gl/BUILD.gn27
-rw-r--r--chromium/ui/gl/PRESUBMIT.py8
-rw-r--r--chromium/ui/gl/egl_bindings_autogen_mock.cc52
-rw-r--r--chromium/ui/gl/egl_bindings_autogen_mock.h26
-rw-r--r--chromium/ui/gl/features.gni10
-rwxr-xr-xchromium/ui/gl/generate_bindings.py31
-rw-r--r--chromium/ui/gl/gl_bindings_api_autogen_gl.h16
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_egl.cc4
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.cc81
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.h32
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.cc12
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.h32
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_osmesa.cc4
-rw-r--r--chromium/ui/gl/gl_context_cgl.cc7
-rw-r--r--chromium/ui/gl/gl_context_egl.cc68
-rw-r--r--chromium/ui/gl/gl_context_egl.h6
-rw-r--r--chromium/ui/gl/gl_context_glx_unittest.cc11
-rw-r--r--chromium/ui/gl/gl_fence.h3
-rw-r--r--chromium/ui/gl/gl_fence_android_native_fence_sync.cc1
-rw-r--r--chromium/ui/gl/gl_fence_egl.cc1
-rw-r--r--chromium/ui/gl/gl_gl_api_implementation.cc1
-rw-r--r--chromium/ui/gl/gl_image.h3
-rw-r--r--chromium/ui/gl/gl_image_ahardwarebuffer.cc3
-rw-r--r--chromium/ui/gl/gl_image_ahardwarebuffer.h4
-rw-r--r--chromium/ui/gl/gl_image_dxgi.cc10
-rw-r--r--chromium/ui/gl/gl_image_dxgi.h3
-rw-r--r--chromium/ui/gl/gl_image_egl.h11
-rw-r--r--chromium/ui/gl/gl_image_glx.cc23
-rw-r--r--chromium/ui/gl/gl_image_glx.h5
-rw-r--r--chromium/ui/gl/gl_image_io_surface.h4
-rw-r--r--chromium/ui/gl/gl_image_io_surface.mm67
-rw-r--r--chromium/ui/gl/gl_image_io_surface_egl.h1
-rw-r--r--chromium/ui/gl/gl_image_io_surface_egl.mm142
-rw-r--r--chromium/ui/gl/gl_image_memory.cc64
-rw-r--r--chromium/ui/gl/gl_image_memory.h5
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap.cc77
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap.h5
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap_unittest.cc1
-rw-r--r--chromium/ui/gl/gl_image_shared_memory_unittest.cc8
-rw-r--r--chromium/ui/gl/gl_image_stub.cc3
-rw-r--r--chromium/ui/gl/gl_image_stub.h3
-rw-r--r--chromium/ui/gl/gl_image_surface_texture.cc3
-rw-r--r--chromium/ui/gl/gl_image_surface_texture.h3
-rw-r--r--chromium/ui/gl/gl_implementation.cc1
-rw-r--r--chromium/ui/gl/gl_implementation_osmesa.cc9
-rw-r--r--chromium/ui/gl/gl_mock_autogen_egl.h16
-rw-r--r--chromium/ui/gl/gl_mock_autogen_gl.h16
-rw-r--r--chromium/ui/gl/gl_stub_autogen_gl.cc11
-rw-r--r--chromium/ui/gl/gl_stub_autogen_gl.h16
-rw-r--r--chromium/ui/gl/gl_surface.cc10
-rw-r--r--chromium/ui/gl/gl_surface.h8
-rw-r--r--chromium/ui/gl/gl_surface_egl.cc73
-rw-r--r--chromium/ui/gl/gl_surface_egl.h3
-rw-r--r--chromium/ui/gl/gl_surface_glx.cc86
-rw-r--r--chromium/ui/gl/gl_surface_overlay.cc8
-rw-r--r--chromium/ui/gl/gl_surface_overlay.h4
-rw-r--r--chromium/ui/gl/gl_surface_wgl.cc40
-rw-r--r--chromium/ui/gl/init/BUILD.gn2
-rw-r--r--chromium/ui/gl/init/create_gr_gl_interface.cc9
-rw-r--r--chromium/ui/gl/init/gl_factory_mac.cc6
-rw-r--r--chromium/ui/gl/init/gl_initializer_mac.cc40
-rw-r--r--chromium/ui/gl/yuv_to_rgb_converter.cc37
-rw-r--r--chromium/ui/keyboard/BUILD.gn31
-rw-r--r--chromium/ui/keyboard/container_behavior.h9
-rw-r--r--chromium/ui/keyboard/container_floating_behavior.cc148
-rw-r--r--chromium/ui/keyboard/container_floating_behavior.h10
-rw-r--r--chromium/ui/keyboard/container_floating_behavior_unittest.cc7
-rw-r--r--chromium/ui/keyboard/container_full_width_behavior.cc20
-rw-r--r--chromium/ui/keyboard/container_full_width_behavior.h6
-rw-r--r--chromium/ui/keyboard/container_full_width_behavior_unittest.cc8
-rw-r--r--chromium/ui/keyboard/content/keyboard.cc27
-rw-r--r--chromium/ui/keyboard/content/keyboard.h19
-rw-r--r--chromium/ui/keyboard/content/keyboard_constants.cc12
-rw-r--r--chromium/ui/keyboard/content/keyboard_constants.h20
-rw-r--r--chromium/ui/keyboard/content/keyboard_content_util.h33
-rw-r--r--chromium/ui/keyboard/display_util.cc72
-rw-r--r--chromium/ui/keyboard/display_util.h27
-rw-r--r--chromium/ui/keyboard/drag_descriptor.cc9
-rw-r--r--chromium/ui/keyboard/drag_descriptor.h15
-rw-r--r--chromium/ui/keyboard/keyboard_controller.cc61
-rw-r--r--chromium/ui/keyboard/keyboard_controller.h14
-rw-r--r--chromium/ui/keyboard/keyboard_controller_unittest.cc86
-rw-r--r--chromium/ui/keyboard/keyboard_event_filter.cc10
-rw-r--r--chromium/ui/keyboard/keyboard_event_filter.h2
-rw-r--r--chromium/ui/keyboard/keyboard_layout_manager.cc16
-rw-r--r--chromium/ui/keyboard/keyboard_resource_util.cc (renamed from chromium/ui/keyboard/content/keyboard_content_util.cc)38
-rw-r--r--chromium/ui/keyboard/keyboard_resource_util.h34
-rw-r--r--chromium/ui/keyboard/keyboard_resources.grd3
-rw-r--r--chromium/ui/keyboard/keyboard_util_unittest.cc1
-rw-r--r--chromium/ui/keyboard/queued_container_type.cc2
-rw-r--r--chromium/ui/keyboard/queued_container_type.h5
-rw-r--r--chromium/ui/keyboard/queued_display_change.cc17
-rw-r--r--chromium/ui/keyboard/queued_display_change.h31
-rw-r--r--chromium/ui/latency/BUILD.gn32
-rw-r--r--chromium/ui/latency/OWNERS4
-rw-r--r--chromium/ui/latency/fixed_point.cc61
-rw-r--r--chromium/ui/latency/fixed_point.h71
-rw-r--r--chromium/ui/latency/fixed_point_unittest.cc149
-rw-r--r--chromium/ui/latency/frame_metrics_test_common.cc92
-rw-r--r--chromium/ui/latency/frame_metrics_test_common.h174
-rw-r--r--chromium/ui/latency/histograms.cc385
-rw-r--r--chromium/ui/latency/histograms.h103
-rw-r--r--chromium/ui/latency/histograms_perftest.cc257
-rw-r--r--chromium/ui/latency/histograms_unittest.cc151
-rw-r--r--chromium/ui/latency/mojo/BUILD.gn1
-rw-r--r--chromium/ui/latency/mojo/latency_info.mojom10
-rw-r--r--chromium/ui/latency/mojo/latency_info_struct_traits.cc2
-rw-r--r--chromium/ui/latency/mojo/latency_info_struct_traits.h1
-rw-r--r--chromium/ui/latency/stream_analyzer.cc186
-rw-r--r--chromium/ui/latency/stream_analyzer.h128
-rw-r--r--chromium/ui/latency/stream_analyzer_unittest.cc312
-rw-r--r--chromium/ui/latency/windowed_analyzer.cc146
-rw-r--r--chromium/ui/latency/windowed_analyzer.h161
-rw-r--r--chromium/ui/latency/windowed_analyzer_unittest.cc470
-rw-r--r--chromium/ui/login/account_picker/md_screen_account_picker.css34
-rw-r--r--chromium/ui/login/account_picker/md_screen_account_picker.js72
-rw-r--r--chromium/ui/login/account_picker/md_user_pod_row.css20
-rw-r--r--chromium/ui/login/account_picker/md_user_pod_row.js162
-rw-r--r--chromium/ui/login/account_picker/screen_account_picker.js1000
-rw-r--r--chromium/ui/login/account_picker/user_pod_row.css2
-rw-r--r--chromium/ui/login/bubble.js43
-rw-r--r--chromium/ui/login/display_manager.js68
-rw-r--r--chromium/ui/login/md_screen_container.css13
-rw-r--r--chromium/ui/message_center/BUILD.gn7
-rw-r--r--chromium/ui/message_center/message_center_impl.cc28
-rw-r--r--chromium/ui/message_center/message_center_observer.h20
-rw-r--r--chromium/ui/message_center/message_center_stats_collector.cc17
-rw-r--r--chromium/ui/message_center/message_center_stats_collector.h7
-rw-r--r--chromium/ui/message_center/notification_list.cc118
-rw-r--r--chromium/ui/message_center/notification_list.h20
-rw-r--r--chromium/ui/message_center/notification_list_unittest.cc55
-rw-r--r--chromium/ui/message_center/public/cpp/notification.cc27
-rw-r--r--chromium/ui/message_center/public/cpp/notification.h29
-rw-r--r--chromium/ui/message_center/public/cpp/notification_delegate.cc27
-rw-r--r--chromium/ui/message_center/public/cpp/notification_delegate.h36
-rw-r--r--chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc8
-rw-r--r--chromium/ui/message_center/public/mojo/BUILD.gn1
-rw-r--r--chromium/ui/message_center/public/mojo/notification.mojom5
-rw-r--r--chromium/ui/message_center/public/mojo/notification_struct_traits.cc13
-rw-r--r--chromium/ui/message_center/public/mojo/notification_struct_traits.h1
-rw-r--r--chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc2
-rw-r--r--chromium/ui/message_center/public/mojo/struct_traits_unittest.cc2
-rw-r--r--chromium/ui/message_center/ui_controller.cc10
-rw-r--r--chromium/ui/message_center/ui_controller.h7
-rw-r--r--chromium/ui/message_center/vector_icons/notification_close_button.1x.icon19
-rw-r--r--chromium/ui/message_center/vector_icons/notification_close_button.icon18
-rw-r--r--chromium/ui/message_center/vector_icons/notification_expand_less.icon3
-rw-r--r--chromium/ui/message_center/vector_icons/notification_expand_more.icon3
-rw-r--r--chromium/ui/message_center/vector_icons/notification_inline_reply.icon3
-rw-r--r--chromium/ui/message_center/vector_icons/notification_settings_button.1x.icon54
-rw-r--r--chromium/ui/message_center/vector_icons/notification_settings_button.icon51
-rw-r--r--chromium/ui/message_center/vector_icons/product.icon3
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.cc14
-rw-r--r--chromium/ui/message_center/views/message_view.cc52
-rw-r--r--chromium/ui/message_center/views/message_view.h28
-rw-r--r--chromium/ui/message_center/views/notification_header_view.cc12
-rw-r--r--chromium/ui/message_center/views/notification_header_view.h3
-rw-r--r--chromium/ui/message_center/views/notification_view.cc51
-rw-r--r--chromium/ui/message_center/views/notification_view.h19
-rw-r--r--chromium/ui/message_center/views/notification_view_md.cc126
-rw-r--r--chromium/ui/message_center/views/notification_view_md.h20
-rw-r--r--chromium/ui/message_center/views/notification_view_md_unittest.cc31
-rw-r--r--chromium/ui/message_center/views/slide_out_controller.cc4
-rw-r--r--chromium/ui/message_center/views/slide_out_controller.h11
-rw-r--r--chromium/ui/message_center/views/toast_contents_view.cc15
-rw-r--r--chromium/ui/native_theme/common_theme.cc8
-rw-r--r--chromium/ui/native_theme/native_theme.h2
-rw-r--r--chromium/ui/native_theme/native_theme_dark_aura.cc2
-rw-r--r--chromium/ui/native_theme/native_theme_mac.mm35
-rw-r--r--chromium/ui/ozone/common/egl_util.cc14
-rw-r--r--chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h3
-rw-r--r--chromium/ui/ozone/common/gpu/ozone_gpu_messages.h4
-rw-r--r--chromium/ui/ozone/demo/BUILD.gn6
-rw-r--r--chromium/ui/ozone/demo/demo_window.cc90
-rw-r--r--chromium/ui/ozone/demo/demo_window.h69
-rw-r--r--chromium/ui/ozone/demo/ozone_demo.cc338
-rw-r--r--chromium/ui/ozone/demo/renderer_factory.cc75
-rw-r--r--chromium/ui/ozone/demo/renderer_factory.h41
-rw-r--r--chromium/ui/ozone/demo/skia_renderer.cc6
-rw-r--r--chromium/ui/ozone/demo/surfaceless_skia_renderer.cc22
-rw-r--r--chromium/ui/ozone/demo/window_manager.cc112
-rw-r--r--chromium/ui/ozone/demo/window_manager.h66
-rw-r--r--chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc10
-rw-r--r--chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc3
-rw-r--r--chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc1
-rw-r--r--chromium/ui/ozone/platform/cast/gl_surface_cast.cc6
-rw-r--r--chromium/ui/ozone/platform/cast/gl_surface_cast.h3
-rw-r--r--chromium/ui/ozone/platform/cast/overlay_manager_cast.cc62
-rw-r--r--chromium/ui/ozone/platform/cast/overlay_manager_cast.h15
-rw-r--r--chromium/ui/ozone/platform/cast/platform_window_cast.cc19
-rw-r--r--chromium/ui/ozone/platform/cast/platform_window_cast.h1
-rw-r--r--chromium/ui/ozone/platform/cast/surface_factory_cast.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.cc61
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.h7
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc59
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc1
-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.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc35
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_buffer.cc5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_buffer.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface.cc4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc91
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h14
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc15
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc41
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/overlay_plane.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/overlay_plane.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.cc8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_cursor.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc44
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc62
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h8
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_overlay_manager.cc6
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_window_host.cc18
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_window_host.h1
-rw-r--r--chromium/ui/ozone/platform/drm/host/gpu_thread_observer.h7
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc1
-rw-r--r--chromium/ui/ozone/platform/headless/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/headless/gl_surface_osmesa_png.cc2
-rw-r--r--chromium/ui/ozone/platform/headless/headless_surface_factory.cc12
-rw-r--r--chromium/ui/ozone/platform/headless/headless_window.cc13
-rw-r--r--chromium/ui/ozone/platform/headless/headless_window.h1
-rw-r--r--chromium/ui/ozone/platform/headless/ozone_platform_headless.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/fake_server.cc123
-rw-r--r--chromium/ui/ozone/platform/wayland/fake_server.h55
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_connection.cc15
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_connection.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc134
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_pointer.cc54
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_pointer.h14
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_pointer_unittest.cc108
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc16
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_test.cc32
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_test.h16
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_touch.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc16
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.cc26
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.h12
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc236
-rw-r--r--chromium/ui/ozone/platform/x11/BUILD.gn7
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc10
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc8
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h7
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone.cc33
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone.h3
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc150
-rw-r--r--chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc43
-rw-r--r--chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h7
-rw-r--r--chromium/ui/ozone/public/interfaces/BUILD.gn2
-rw-r--r--chromium/ui/ozone/public/interfaces/drm_device.mojom10
-rw-r--r--chromium/ui/ozone/public/ozone_gpu_test_helper.cc19
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc10
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h7
-rw-r--r--chromium/ui/platform_window/android/platform_window_android.cc5
-rw-r--r--chromium/ui/platform_window/android/platform_window_android.h1
-rw-r--r--chromium/ui/platform_window/platform_window.h2
-rw-r--r--chromium/ui/platform_window/stub/stub_window.cc4
-rw-r--r--chromium/ui/platform_window/stub/stub_window.h1
-rw-r--r--chromium/ui/platform_window/win/win_window.cc8
-rw-r--r--chromium/ui/platform_window/win/win_window.h1
-rw-r--r--chromium/ui/platform_window/x11/x11_window_base.cc4
-rw-r--r--chromium/ui/platform_window/x11/x11_window_base.h1
-rw-r--r--chromium/ui/resources/BUILD.gn6
-rw-r--r--chromium/ui/resources/default_100_percent/common/emoji_menu_item.pngbin0 -> 496 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/emoji_menu_item.pngbin0 -> 1051 bytes
-rw-r--r--chromium/ui/resources/default_300_percent/common/emoji_menu_item.pngbin0 -> 1554 bytes
-rw-r--r--chromium/ui/resources/ui_resources.grd1
-rw-r--r--chromium/ui/shell_dialogs/BUILD.gn2
-rw-r--r--chromium/ui/shell_dialogs/base_shell_dialog_win.cc1
-rw-r--r--chromium/ui/shell_dialogs/run_all_unittests.cc6
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog.cc2
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.cc42
-rw-r--r--chromium/ui/snapshot/BUILD.gn2
-rw-r--r--chromium/ui/snapshot/snapshot_aura.cc7
-rw-r--r--chromium/ui/strings/translations/ui_strings_am.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ar.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_bg.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_bn.xtb2
-rw-r--r--chromium/ui/strings/translations/ui_strings_ca.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_cs.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_da.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_de.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_el.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_en-GB.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_es-419.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_es.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_et.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_fa.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_fi.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_fil.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_gu.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_hi.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_hr.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_hu.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_id.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_it.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_iw.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ja.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_kn.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ko.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_lt.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_lv.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ml.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_mr.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ms.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_nl.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_no.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_pl.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-BR.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-PT.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ro.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_sk.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_sl.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_sv.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_sw.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_ta.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_te.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_th.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_tr.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_uk.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_vi.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-CN.xtb3
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-TW.xtb3
-rw-r--r--chromium/ui/strings/ui_strings.grd13
-rw-r--r--chromium/ui/touch_selection/touch_handle.cc4
-rw-r--r--chromium/ui/touch_selection/touch_handle.h4
-rw-r--r--chromium/ui/touch_selection/touch_handle_unittest.cc1
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller.cc13
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller.h3
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller_test_api.cc7
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller_test_api.h1
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller_unittest.cc151
-rw-r--r--chromium/ui/views/BUILD.gn35
-rw-r--r--chromium/ui/views/DEPS1
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc7
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc1
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_base.cc87
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_base.h7
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_mac.mm1
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_unittest.cc1
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_win.cc2
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.cc2
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.h3
-rw-r--r--chromium/ui/views/accessible_pane_view.cc1
-rw-r--r--chromium/ui/views/animation/ink_drop.h8
-rw-r--r--chromium/ui/views/animation/ink_drop_highlight_unittest.cc1
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc22
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.h12
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.cc32
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.h15
-rw-r--r--chromium/ui/views/animation/ink_drop_impl_unittest.cc1
-rw-r--r--chromium/ui/views/animation/ink_drop_stub.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_stub.h2
-rw-r--r--chromium/ui/views/background.cc1
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc119
-rw-r--r--chromium/ui/views/bubble/bubble_border.h59
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc5
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate.cc26
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate.h12
-rw-r--r--chromium/ui/views/bubble/info_bubble.cc9
-rw-r--r--chromium/ui/views/bubble/tooltip_icon.cc1
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.cc23
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.h4
-rw-r--r--chromium/ui/views/cocoa/OWNERS1
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.h8
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.mm80
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.h25
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.mm276
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm79
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_nswindow.mm21
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc2
-rw-r--r--chromium/ui/views/controls/button/button.cc1
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc18
-rw-r--r--chromium/ui/views/controls/button/checkbox.h13
-rw-r--r--chromium/ui/views/controls/button/checkbox_unittest.cc65
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.cc1
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.h3
-rw-r--r--chromium/ui/views/controls/button/image_button_factory_unittest.cc5
-rw-r--r--chromium/ui/views/controls/button/label_button.cc1
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc4
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc7
-rw-r--r--chromium/ui/views/controls/button/md_text_button.h6
-rw-r--r--chromium/ui/views/controls/button/menu_button_unittest.cc3
-rw-r--r--chromium/ui/views/controls/button/toggle_button_unittest.cc1
-rw-r--r--chromium/ui/views/controls/focus_ring.cc59
-rw-r--r--chromium/ui/views/controls/focus_ring.h33
-rw-r--r--chromium/ui/views/controls/image_view.cc8
-rw-r--r--chromium/ui/views/controls/image_view.h6
-rw-r--r--chromium/ui/views/controls/image_view_unittest.cc1
-rw-r--r--chromium/ui/views/controls/label.cc19
-rw-r--r--chromium/ui/views/controls/label.h9
-rw-r--r--chromium/ui/views/controls/label_unittest.cc15
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.h74
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.mm100
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc15
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h37
-rw-r--r--chromium/ui/views/controls/menu/menu_config_mac.mm51
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc82
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h25
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc4
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.cc35
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.h1
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc68
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h9
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc47
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.h3
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm26
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_unittest.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_types.h4
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc1
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc13
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h2
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc9
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h7
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc11
-rw-r--r--chromium/ui/views/controls/progress_bar_unittest.cc7
-rw-r--r--chromium/ui/views/controls/scroll_view.cc13
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc454
-rw-r--r--chromium/ui/views/controls/styled_label.cc10
-rw-r--r--chromium/ui/views/controls/styled_label.h1
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc4
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc9
-rw-r--r--chromium/ui/views/controls/table/table_header.cc14
-rw-r--r--chromium/ui/views/controls/table/table_view.cc11
-rw-r--r--chromium/ui/views/controls/table/table_view.h2
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc90
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc111
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h56
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc15
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc44
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc164
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc11
-rw-r--r--chromium/ui/views/controls/tree/tree_view_unittest.cc1
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu.h8
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_mac.mm92
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc4
-rw-r--r--chromium/ui/views/controls/webview/webview.cc8
-rw-r--r--chromium/ui/views/controls/webview/webview.h7
-rw-r--r--chromium/ui/views/controls/webview/webview_unittest.cc10
-rw-r--r--chromium/ui/views/examples/box_layout_example.cc5
-rw-r--r--chromium/ui/views/examples/examples_main.cc8
-rw-r--r--chromium/ui/views/examples/examples_window.cc1
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.cc1
-rw-r--r--chromium/ui/views/examples/text_example.cc1
-rw-r--r--chromium/ui/views/examples/tree_view_example.cc1
-rw-r--r--chromium/ui/views/focus/external_focus_tracker.cc1
-rw-r--r--chromium/ui/views/focus/focus_manager.cc1
-rw-r--r--chromium/ui/views/focus/focus_manager_factory.cc1
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc1
-rw-r--r--chromium/ui/views/focus/focus_traversal_unittest.cc1
-rw-r--r--chromium/ui/views/layout/box_layout.cc30
-rw-r--r--chromium/ui/views/layout/box_layout.h17
-rw-r--r--chromium/ui/views/layout/box_layout_unittest.cc27
-rw-r--r--chromium/ui/views/layout/layout_provider.cc9
-rw-r--r--chromium/ui/views/layout/layout_provider.h9
-rw-r--r--chromium/ui/views/linux_ui/OWNERS2
-rw-r--r--chromium/ui/views/mouse_watcher.cc7
-rw-r--r--chromium/ui/views/mus/BUILD.gn9
-rw-r--r--chromium/ui/views/mus/DEPS2
-rw-r--r--chromium/ui/views/mus/aura_init.cc2
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc35
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h6
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc1
-rw-r--r--chromium/ui/views/mus/drag_interactive_uitest.cc24
-rw-r--r--chromium/ui/views/mus/mus_client.cc15
-rw-r--r--chromium/ui/views/mus/mus_client.h10
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc1
-rw-r--r--chromium/ui/views/mus/remote_view/BUILD.gn66
-rw-r--r--chromium/ui/views/mus/remote_view/README.md55
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.cc76
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.h60
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc151
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.cc154
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.h98
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc18
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h29
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc169
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc14
-rw-r--r--chromium/ui/views/painter.cc1
-rw-r--r--chromium/ui/views/selection_controller.cc5
-rw-r--r--chromium/ui/views/style/platform_style.cc13
-rw-r--r--chromium/ui/views/style/platform_style.h16
-rw-r--r--chromium/ui/views/style/platform_style_mac.mm40
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc9
-rw-r--r--chromium/ui/views/vector_icons/checkbox_active.icon4
-rw-r--r--chromium/ui/views/vector_icons/checkbox_normal.icon4
-rw-r--r--chromium/ui/views/vector_icons/close.icon31
-rw-r--r--chromium/ui/views/vector_icons/ic_close.icon33
-rw-r--r--chromium/ui/views/vector_icons/info.icon29
-rw-r--r--chromium/ui/views/vector_icons/launch.icon31
-rw-r--r--chromium/ui/views/vector_icons/menu_check.1x.icon14
-rw-r--r--chromium/ui/views/vector_icons/menu_check.icon13
-rw-r--r--chromium/ui/views/vector_icons/menu_radio_empty.icon3
-rw-r--r--chromium/ui/views/vector_icons/menu_radio_selected.icon3
-rw-r--r--chromium/ui/views/vector_icons/new_incognito_window.icon40
-rw-r--r--chromium/ui/views/vector_icons/new_tab.icon28
-rw-r--r--chromium/ui/views/vector_icons/new_window.icon34
-rw-r--r--chromium/ui/views/vector_icons/open.icon15
-rw-r--r--chromium/ui/views/vector_icons/options.icon17
-rw-r--r--chromium/ui/views/vector_icons/pin.icon32
-rw-r--r--chromium/ui/views/vector_icons/radio_button_active.icon3
-rw-r--r--chromium/ui/views/vector_icons/radio_button_normal.icon3
-rw-r--r--chromium/ui/views/vector_icons/submenu_arrow.1x.icon12
-rw-r--r--chromium/ui/views/vector_icons/submenu_arrow.icon11
-rw-r--r--chromium/ui/views/vector_icons/uninstall.icon27
-rw-r--r--chromium/ui/views/vector_icons/unpin.icon23
-rw-r--r--chromium/ui/views/view.cc5
-rw-r--r--chromium/ui/views/view_tracker_unittest.cc1
-rw-r--r--chromium/ui/views/view_unittest.cc17
-rw-r--r--chromium/ui/views/views_delegate.cc1
-rw-r--r--chromium/ui/views/views_perftests.cc3
-rw-r--r--chromium/ui/views/views_test_suite.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/OWNERS5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc1
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc29
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc73
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc426
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h116
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc84
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc60
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h17
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc1
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc1
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc6
-rw-r--r--chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc1
-rw-r--r--chromium/ui/views/widget/native_widget_delegate.h3
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm17
-rw-r--r--chromium/ui/views/widget/root_view.cc5
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc5
-rw-r--r--chromium/ui/views/widget/widget.cc14
-rw-r--r--chromium/ui/views/widget/widget.h10
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc7
-rw-r--r--chromium/ui/views/widget/widget_delegate.h10
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc18
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc8
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc182
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h29
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h10
-rw-r--r--chromium/ui/views/win/pen_event_processor.cc1
-rw-r--r--chromium/ui/views/word_lookup_client.h10
-rw-r--r--chromium/ui/web_dialogs/BUILD.gn3
-rw-r--r--chromium/ui/web_dialogs/DEPS3
-rw-r--r--chromium/ui/web_dialogs/web_dialog_ui.cc72
-rw-r--r--chromium/ui/web_dialogs/web_dialog_ui.h81
-rw-r--r--chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc2
-rw-r--r--chromium/ui/webui/BUILD.gn17
-rw-r--r--chromium/ui/webui/DEPS3
-rw-r--r--chromium/ui/webui/PLATFORM_OWNERS1
-rw-r--r--chromium/ui/webui/mojo_web_ui_controller.cc21
-rw-r--r--chromium/ui/webui/mojo_web_ui_controller.h78
-rw-r--r--chromium/ui/webui/resources/BUILD.gn13
-rw-r--r--chromium/ui/webui/resources/PRESUBMIT.py27
-rw-r--r--chromium/ui/webui/resources/cr_components/BUILD.gn12
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/BUILD.gn128
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html54
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn38
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn117
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js9
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html12
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js11
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html35
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js99
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html21
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn19
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html38
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js13
-rw-r--r--chromium/ui/webui/resources/cr_elements/BUILD.gn38
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn13
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html24
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html10
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn66
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html9
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js38
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js4
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn20
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js55
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn19
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html56
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js52
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html25
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js17
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_icons_css.html67
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html7
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js17
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn18
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html25
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js6
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn26
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js17
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn17
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn14
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html46
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js59
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn19
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js21
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn32
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html20
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html9
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html15
-rw-r--r--chromium/ui/webui/resources/cr_elements/icons.html1
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/BUILD.gn62
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js5
-rw-r--r--chromium/ui/webui/resources/images/icon_error_outline.svg (renamed from chromium/ui/webui/resources/images/fingerprint_failed.svg)0
-rw-r--r--chromium/ui/webui/resources/js/BUILD.gn37
-rw-r--r--chromium/ui/webui/resources/js/cr/BUILD.gn24
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/BUILD.gn250
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js2
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/grid.js2
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list.js36
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/BUILD.gn42
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/table/table_header.js3
-rw-r--r--chromium/ui/webui/resources/polymer_resources.grdp12
-rw-r--r--chromium/ui/webui/webui_features.gni15
-rw-r--r--chromium/ui/wm/BUILD.gn7
-rw-r--r--chromium/ui/wm/core/DEPS1
-rw-r--r--chromium/ui/wm/core/easy_resize_window_targeter_unittest.cc9
-rw-r--r--chromium/ui/wm/core/focus_controller_unittest.cc4
-rw-r--r--chromium/ui/wm/core/shadow_controller.cc18
-rw-r--r--chromium/ui/wm/core/shadow_controller.h7
-rw-r--r--chromium/ui/wm/core/shadow_controller_unittest.cc18
-rw-r--r--chromium/ui/wm/core/window_animations.cc1
-rw-r--r--chromium/ui/wm/core/window_util.cc1
-rw-r--r--chromium/ui/wm/core/wm_state.cc1
1195 files changed, 29368 insertions, 12053 deletions
diff --git a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.h b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.h
index ba03959d822..0a20628daa2 100644
--- a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.h
+++ b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -58,6 +58,7 @@ class ACCELERATED_WIDGET_MAC_EXPORT AcceleratedWidgetMac
void SetNSView(AcceleratedWidgetMacNSView* view);
void ResetNSView();
+ void ResetNSViewPreservingContents();
// Return true if the last frame swapped has a size in DIP of |dip_size|.
bool HasFrameOfSize(const gfx::Size& dip_size) const;
diff --git a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm
index 8306398431d..97e7b502f15 100644
--- a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm
+++ b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm
@@ -94,6 +94,15 @@ void AcceleratedWidgetMac::ResetNSView() {
view_ = NULL;
}
+void AcceleratedWidgetMac::ResetNSViewPreservingContents() {
+ if (!view_)
+ return;
+
+ ScopedCAActionDisabler disabler;
+ [flipped_layer_ removeFromSuperlayer];
+ view_ = NULL;
+}
+
bool AcceleratedWidgetMac::HasFrameOfSize(
const gfx::Size& dip_size) const {
return last_swap_size_dip_ == dip_size;
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn
index d497360d8d8..1b7ba545cdf 100644
--- a/chromium/ui/accessibility/BUILD.gn
+++ b/chromium/ui/accessibility/BUILD.gn
@@ -20,6 +20,12 @@ mojom("ax_enums_mojo") {
sources = [
"ax_enums.mojom",
]
+
+ public_deps = [
+ "//mojo/public/mojom/base",
+ "//ui/gfx/geometry/mojo",
+ "//ui/gfx/mojo",
+ ]
}
component("accessibility") {
@@ -172,10 +178,14 @@ test("accessibility_unittests") {
"ax_tree_combiner_unittest.cc",
"ax_tree_serializer_unittest.cc",
"ax_tree_unittest.cc",
+ "mojom/ax_node_data_mojom_traits_unittest.cc",
+ "mojom/ax_tree_data_mojom_traits_unittest.cc",
+ "mojom/ax_tree_update_mojom_traits_unittest.cc",
"platform/ax_platform_node_unittest.cc",
"platform/ax_platform_node_unittest.h",
"platform/ax_platform_node_win_unittest.cc",
"platform/ax_unique_id_unittest.cc",
+ "run_all_unittests.cc",
]
deps = [
@@ -183,9 +193,14 @@ test("accessibility_unittests") {
":ax_enums_mojo",
":test_support",
"//base",
- "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//mojo/common",
+ "//mojo/edk",
+ "//mojo/edk/test:test_support",
+ "//mojo/public/cpp/test_support:test_utils",
"//skia",
"//testing/gtest",
+ "//ui/accessibility/mojom",
"//ui/base",
"//ui/gfx",
"//ui/gfx/geometry",
diff --git a/chromium/ui/accessibility/DEPS b/chromium/ui/accessibility/DEPS
index de7564af66b..33a31c8668a 100644
--- a/chromium/ui/accessibility/DEPS
+++ b/chromium/ui/accessibility/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+mojo/public",
"+third_party/iaccessible2",
"+third_party/skia",
"+ui/aura",
@@ -8,3 +9,9 @@ include_rules = [
"+ui/gfx",
"+ui/strings/grit/ui_strings.h",
]
+
+specific_include_rules = {
+ "run_all_unittests.cc": [
+ "+mojo/edk/embedder",
+ ]
+}
diff --git a/chromium/ui/accessibility/PRESUBMIT.py b/chromium/ui/accessibility/PRESUBMIT.py
index 500b1cc607e..b0d403420f7 100644
--- a/chromium/ui/accessibility/PRESUBMIT.py
+++ b/chromium/ui/accessibility/PRESUBMIT.py
@@ -115,12 +115,16 @@ def CheckEnumsMatch(input_api, output_api):
output_api)
CheckMatchingEnum(ax_enums, 'State', automation_enums, 'StateType', errs,
output_api)
+ CheckMatchingEnum(ax_enums, 'Action', automation_enums, 'ActionType', errs,
+ output_api)
CheckMatchingEnum(ax_enums, 'Event', automation_enums, 'EventType', errs,
output_api)
CheckMatchingEnum(ax_enums, 'NameFrom', automation_enums, 'NameFromType',
errs, output_api)
CheckMatchingEnum(ax_enums, 'Restriction', automation_enums,
'Restriction', errs, output_api)
+ CheckMatchingEnum(ax_enums, 'DefaultActionVerb', automation_enums,
+ 'DefaultActionVerb', errs, output_api)
return errs
# Given a full path to c++ header, return an array of the first static
diff --git a/chromium/ui/accessibility/ax_enum_util.cc b/chromium/ui/accessibility/ax_enum_util.cc
index f47b11a714e..8c80b463557 100644
--- a/chromium/ui/accessibility/ax_enum_util.cc
+++ b/chromium/ui/accessibility/ax_enum_util.cc
@@ -32,6 +32,8 @@ const char* ToString(ax::mojom::Event event) {
return "expandedChanged";
case ax::mojom::Event::kFocus:
return "focus";
+ case ax::mojom::Event::kFocusContext:
+ return "focusContext";
case ax::mojom::Event::kHide:
return "hide";
case ax::mojom::Event::kHitTestResult:
@@ -98,6 +100,8 @@ const char* ToString(ax::mojom::Event event) {
return "selectionRemove";
case ax::mojom::Event::kShow:
return "show";
+ case ax::mojom::Event::kStateChanged:
+ return "stateChanged";
case ax::mojom::Event::kTextChanged:
return "textChanged";
case ax::mojom::Event::kTextSelectionChanged:
@@ -784,10 +788,6 @@ const char* ToString(ax::mojom::State state) {
return "required";
case ax::mojom::State::kRichlyEditable:
return "richlyEditable";
- case ax::mojom::State::kSelectable:
- return "selectable";
- case ax::mojom::State::kSelected:
- return "selected";
case ax::mojom::State::kVertical:
return "vertical";
case ax::mojom::State::kVisited:
@@ -832,10 +832,6 @@ ax::mojom::State ParseState(const char* state) {
return ax::mojom::State::kRequired;
if (0 == strcmp(state, "richlyEditable"))
return ax::mojom::State::kRichlyEditable;
- if (0 == strcmp(state, "selectable"))
- return ax::mojom::State::kSelectable;
- if (0 == strcmp(state, "selected"))
- return ax::mojom::State::kSelected;
if (0 == strcmp(state, "vertical"))
return ax::mojom::State::kVertical;
if (0 == strcmp(state, "visited"))
@@ -1435,6 +1431,8 @@ const char* ToString(ax::mojom::BoolAttribute bool_attribute) {
return "clickable";
case ax::mojom::BoolAttribute::kClipsChildren:
return "clipsChildren";
+ case ax::mojom::BoolAttribute::kSelected:
+ return "selected";
}
return "";
@@ -1465,6 +1463,8 @@ ax::mojom::BoolAttribute ParseBoolAttribute(const char* bool_attribute) {
return ax::mojom::BoolAttribute::kClickable;
if (0 == strcmp(bool_attribute, "clipsChildren"))
return ax::mojom::BoolAttribute::kClipsChildren;
+ if (0 == strcmp(bool_attribute, "selected"))
+ return ax::mojom::BoolAttribute::kSelected;
return ax::mojom::BoolAttribute::kNone;
}
diff --git a/chromium/ui/accessibility/ax_enums.mojom b/chromium/ui/accessibility/ax_enums.mojom
index 7d0d2a3e026..773dbf24d71 100644
--- a/chromium/ui/accessibility/ax_enums.mojom
+++ b/chromium/ui/accessibility/ax_enums.mojom
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// TODO(nektar): Migrate entire file to Mojoq.
// Must also be kept in sync with chrome/common/extensions/api/automation.idl.
module ax.mojom;
@@ -10,19 +9,22 @@ module ax.mojom;
// chrome/common/extensions/api/automation.idl. This is enforced
// by a PRESUBMIT check.
//
- // Explanation of the comments next to these events:
+ // Explanation of in-lined comments next to some enum values/attributes:
//
- // Web: this event is only used in web content. Unless a specific platform
- // is specified, it fires a native event on multiple platforms.
+ // Web: this attribute is only used in web content.
//
- // Native: this event is only used in native UI.
+ // Native: this attribute is only used in native UI.
//
- // Implicit: it would be cleaner if we just updated the AX node
- // and each platform fired the appropriate events to indicate which
+ // Implicit: for events, it would be cleaner if we just updated the AX node and
+ // each platform fired the appropriate events to indicate which
// platform-specific attributes changed.
//
- // If unspecified, the event is used across web and native on multiple
+ // if Native / [Platform1, ...] is specified, the attribute is only used
+ // on those platforms.
+ //
+ // If unspecified, the atribute is used across web and native on multiple
// platforms.
+
enum Event {
kNone,
kActiveDescendantChanged, // Web
@@ -36,6 +38,7 @@ enum Event {
kDocumentSelectionChanged,
kExpandedChanged, // Web
kFocus,
+ kFocusContext, // Contextual focus event that must delay the next focus event
kHide, // Remove: http://crbug.com/392502
kHitTestResult,
kHover,
@@ -46,8 +49,8 @@ enum Event {
kLiveRegionChanged, // Web
kLoadComplete, // Web
kLocationChanged, // Web
- kMediaStartedPlaying, // Automation
- kMediaStoppedPlaying, // Automation
+ kMediaStartedPlaying, // Native / Automation
+ kMediaStoppedPlaying, // Native / Automation
kMenuEnd, // Native / Win
kMenuListItemSelected, // Web
kMenuListValueChanged, // Web
@@ -69,13 +72,13 @@ enum Event {
kSelectionAdd, // Native
kSelectionRemove, // Native
kShow, // Remove: http://crbug.com/392502
+ kStateChanged, // Native / Automation
kTextChanged,
kTextSelectionChanged,
kTreeChanged, // Accessibility tree changed. Don't
// explicitly fire an accessibility event,
// only implicitly due to the change.
kValueChanged,
- kLast = kValueChanged,
};
// Explanation:
@@ -216,7 +219,6 @@ enum Role {
kWebArea,
kWebView,
kWindow,
- kLast = kWindow,
};
enum State {
@@ -239,12 +241,9 @@ enum State {
kProtected,
kRequired,
kRichlyEditable,
- kSelectable,
- kSelected,
// Grows vertically, e.g. menu or combo box.
kVertical,
kVisited,
- kLast = kVisited,
};
// An action to be taken on an accessibility node.
@@ -286,11 +285,11 @@ enum Action {
// Scrolls by approximately one screen in a specific direction. Should be
// called on a node that has scrollable boolean set to true.
kScrollBackward,
- kScrollForward,
- kScrollUp,
kScrollDown,
+ kScrollForward,
kScrollLeft,
kScrollRight,
+ kScrollUp,
// Scroll any scrollable containers to make the target object visible
// on the screen. Optionally pass a subfocus rect in
@@ -314,14 +313,12 @@ enum Action {
kSetValue,
kShowContextMenu,
- kLast = kShowContextMenu,
};
enum ActionFlags {
kNone,
kRequestImages,
kRequestInlineTextBoxes,
- kLast = kRequestInlineTextBoxes,
};
// A list of valid values for the |AXIntAttribute| |default_action_verb|.
@@ -347,7 +344,6 @@ enum DefaultActionVerb {
kPress,
kSelect,
kUncheck,
- kLast = kUncheck,
};
// A change to the accessibility tree.
@@ -357,7 +353,6 @@ enum Mutation {
kSubtreeCreated,
kNodeChanged,
kNodeRemoved,
- kLast = kNodeRemoved,
};
enum StringAttribute {
@@ -366,8 +361,8 @@ enum StringAttribute {
// Only used when invalid_state == invalid_state_other.
kAriaInvalidValue,
kAutoComplete,
- kChromeChannel, // Automation only.
- kClassName, // views and Android
+ kChromeChannel, // Native / Automation
+ kClassName, // Native / Android
kContainerLiveRelevant,
kContainerLiveStatus,
kDescription,
@@ -388,7 +383,6 @@ enum StringAttribute {
kRoleDescription,
kUrl,
kValue,
- kLast = kValue,
};
enum IntAttribute {
@@ -493,7 +487,6 @@ enum IntAttribute {
// Focus traversal in views and Android.
kPreviousFocusId,
kNextFocusId,
- kLast = kNextFocusId,
};
enum FloatAttribute {
@@ -507,9 +500,16 @@ enum FloatAttribute {
// Text attributes.
// Font size is in pixels.
kFontSize,
- kLast = kFontSize,
};
+// These attributes can take three states:
+// true, false, or undefined/unset.
+//
+// Some attributes are only ever true or unset. In these cases, undefined is
+// equivalent to false. In other attributes, all three states have meaning.
+//
+// Finally, note that different tree sources can use all three states for a
+// given attribute, while another tree source only uses two.
enum BoolAttribute {
kNone,
// Generic busy state, does not have to be on a live region.
@@ -542,7 +542,9 @@ enum BoolAttribute {
// Indicates that this node clips its children, i.e. may have
// overflow: hidden or clip children by default.
kClipsChildren,
- kLast = kClipsChildren,
+
+ // Indicates whether this node is selected or unselected.
+ kSelected,
};
enum IntListAttribute {
@@ -605,7 +607,6 @@ enum IntListAttribute {
// items. Developer can expose those actions as custom actions. Currently
// custom actions are used only in Android window.
kCustomActionIds,
- kLast = kCustomActionIds,
};
enum StringListAttribute {
@@ -613,7 +614,6 @@ enum StringListAttribute {
// Descriptions for custom actions. This must be aligned with
// custom_action_ids.
kCustomActionDescriptions,
- kLast = kCustomActionDescriptions,
};
// TODO(dmazzoni, nektar): make this list not grow exponentially as new
@@ -655,7 +655,6 @@ enum MarkerType {
kSpellingTextMatchActiveSuggestionSuggestion = 53,
kGrammarTextMatchActiveSuggestionSuggestion = 54,
kSpellingGrammarTextMatchActiveSuggestionSuggestion = 55,
- kLast = kSpellingGrammarTextMatchActiveSuggestionSuggestion,
};
enum TextDirection {
@@ -664,7 +663,6 @@ enum TextDirection {
kRtl,
kTtb,
kBtt,
- kLast = kBtt,
};
// A Java counterpart will be generated for this enum.
@@ -687,7 +685,6 @@ enum TextStyle {
kTextStyleBoldUnderlineLineThrough = 13,
kTextStyleItalicUnderlineLineThrough = 14,
kTextStyleBoldItalicUnderlineLineThrough = 15,
- kLast = kTextStyleBoldItalicUnderlineLineThrough,
};
enum AriaCurrentState {
@@ -700,7 +697,6 @@ enum AriaCurrentState {
kUnclippedLocation,
kDate,
kTime,
- kLast = kTime,
};
enum InvalidState {
@@ -710,7 +706,6 @@ enum InvalidState {
kSpelling,
kGrammar,
kOther,
- kLast = kOther,
};
// Input restriction associated with an object.
@@ -721,7 +716,6 @@ enum Restriction {
kNone,
kReadOnly,
kDisabled,
- kLast = kDisabled,
};
enum CheckedState {
@@ -729,7 +723,6 @@ enum CheckedState {
kFalse,
kTrue,
kMixed,
- kLast = kMixed,
};
enum SortDirection {
@@ -738,7 +731,6 @@ enum SortDirection {
kAscending,
kDescending,
kOther,
- kLast = kOther,
};
enum NameFrom {
@@ -750,7 +742,6 @@ enum NameFrom {
kPlaceholder,
kRelatedElement,
kValue,
- kLast = kValue,
};
enum DescriptionFrom {
@@ -760,7 +751,6 @@ enum DescriptionFrom {
kContents,
kPlaceholder,
kRelatedElement,
- kLast = kRelatedElement,
};
enum EventFrom {
@@ -768,7 +758,6 @@ enum EventFrom {
kUser,
kPage,
kAction,
- kLast = kAction,
};
// Touch gestures on Chrome OS.
@@ -792,14 +781,12 @@ enum Gesture {
kSwipeRight4,
kSwipeDown4,
kTap2,
- kLast = kTap2,
};
enum TextAffinity {
kNone,
kDownstream,
kUpstream,
- kLast = kUpstream,
};
// Compares two nodes in an accessibility tree in pre-order traversal.
@@ -816,5 +803,4 @@ enum TreeOrder {
// First node is after the second one.
kAfter,
- kLast = kAfter,
};
diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc
index 52747b1632b..2c132265225 100644
--- a/chromium/ui/accessibility/ax_event_generator.cc
+++ b/chromium/ui/accessibility/ax_event_generator.cc
@@ -141,16 +141,6 @@ void AXEventGenerator::OnStateChanged(AXTree* tree,
AddEvent(container, Event::ROW_COUNT_CHANGED);
}
break;
- case ax::mojom::State::kSelected: {
- AddEvent(node, Event::SELECTED_CHANGED);
- ui::AXNode* container = node;
- while (container &&
- !ui::IsContainerWithSelectableChildrenRole(container->data().role))
- container = container->parent();
- if (container)
- AddEvent(container, Event::SELECTED_CHILDREN_CHANGED);
- break;
- }
case ax::mojom::State::kIgnored: {
ui::AXNode* unignored_parent = node->GetUnignoredParent();
if (unignored_parent)
@@ -251,6 +241,17 @@ void AXEventGenerator::OnBoolAttributeChanged(AXTree* tree,
bool new_value) {
DCHECK_EQ(tree_, tree);
+ if (attr == ax::mojom::BoolAttribute::kSelected) {
+ AddEvent(node, Event::SELECTED_CHANGED);
+ ui::AXNode* container = node;
+ while (container &&
+ !ui::IsContainerWithSelectableChildrenRole(container->data().role))
+ container = container->parent();
+ if (container)
+ AddEvent(container, Event::SELECTED_CHILDREN_CHANGED);
+ return;
+ }
+
AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
}
@@ -411,7 +412,10 @@ void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
return;
source_nodes.insert(source_node);
- AddEvent(source_node, Event::RELATED_NODE_CHANGED);
+
+ // GCC < 6.4 requires this pointer when calling a member
+ // function in anonymous function
+ this->AddEvent(source_node, Event::RELATED_NODE_CHANGED);
});
};
diff --git a/chromium/ui/accessibility/ax_event_generator_unittest.cc b/chromium/ui/accessibility/ax_event_generator_unittest.cc
index 2d3f192568f..2cbbb9e02ab 100644
--- a/chromium/ui/accessibility/ax_event_generator_unittest.cc
+++ b/chromium/ui/accessibility/ax_event_generator_unittest.cc
@@ -228,20 +228,23 @@ TEST(AXEventGeneratorTest, SelectedAndSelectedChildren) {
initial_state.nodes[2].role = ax::mojom::Role::kMenuItem;
initial_state.nodes[3].id = 4;
initial_state.nodes[3].role = ax::mojom::Role::kListBoxOption;
- initial_state.nodes[3].AddState(ax::mojom::State::kSelected);
+ initial_state.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+ true);
AXTree tree(initial_state);
AXEventGenerator event_generator(&tree);
AXTreeUpdate update = initial_state;
- update.nodes[2].AddState(ax::mojom::State::kSelected);
- update.nodes[3].state = 0;
+ update.nodes[2].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes.pop_back();
+ update.nodes.emplace_back();
+ update.nodes[3].id = 4;
+ update.nodes[3].role = ax::mojom::Role::kListBoxOption;
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, false);
EXPECT_TRUE(tree.Unserialize(update));
EXPECT_EQ(
"SELECTED_CHANGED on 3, "
"SELECTED_CHANGED on 4, "
- "SELECTED_CHILDREN_CHANGED on 2, "
- "STATE_CHANGED on 3, "
- "STATE_CHANGED on 4",
+ "SELECTED_CHILDREN_CHANGED on 2",
DumpEvents(&event_generator));
}
diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc
index 5f8967f3698..ac0c81ea87a 100644
--- a/chromium/ui/accessibility/ax_node_data.cc
+++ b/chromium/ui/accessibility/ax_node_data.cc
@@ -32,7 +32,7 @@ uint32_t ModifyFlag(uint32_t bitfield, uint32_t flag, bool set) {
std::string StateBitfieldToString(uint32_t state) {
std::string str;
for (uint32_t i = static_cast<uint32_t>(ax::mojom::State::kNone) + 1;
- i <= static_cast<uint32_t>(ax::mojom::State::kLast); ++i) {
+ i <= static_cast<uint32_t>(ax::mojom::State::kMaxValue); ++i) {
if (IsFlagSet(state, i))
str += " " +
base::ToUpperASCII(ui::ToString(static_cast<ax::mojom::State>(i)));
@@ -43,7 +43,7 @@ std::string StateBitfieldToString(uint32_t state) {
std::string ActionsBitfieldToString(uint32_t actions) {
std::string str;
for (uint32_t i = static_cast<uint32_t>(ax::mojom::Action::kNone) + 1;
- i <= static_cast<uint32_t>(ax::mojom::Action::kLast); ++i) {
+ i <= static_cast<uint32_t>(ax::mojom::Action::kMaxValue); ++i) {
if (IsFlagSet(actions, i)) {
str += ui::ToString(static_cast<ax::mojom::Action>(i));
actions = ModifyFlag(actions, i, false);
@@ -1001,6 +1001,9 @@ std::string AXNodeData::ToString() const {
case ax::mojom::BoolAttribute::kClipsChildren:
result += " clips_children=" + value;
break;
+ case ax::mojom::BoolAttribute::kSelected:
+ result += " selected=" + value;
+ break;
case ax::mojom::BoolAttribute::kNone:
break;
}
diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h
index e3ed7ee6a46..67726fa1b31 100644
--- a/chromium/ui/accessibility/ax_position.h
+++ b/chromium/ui/accessibility/ax_position.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <ostream>
#include <string>
#include <utility>
#include <vector>
@@ -1319,6 +1320,13 @@ bool operator>=(const AXPosition<AXPositionType, AXNodeType>& first,
return first == second || first > second;
}
+template <class AXPositionType, class AXNodeType>
+std::ostream& operator<<(
+ std::ostream& stream,
+ const AXPosition<AXPositionType, AXNodeType>& position) {
+ return stream << position.ToString();
+}
+
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_POSITION_H_
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index b6fe217c0b0..a7de4473d1a 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -269,8 +269,8 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node,
// Here we are extending the definition of offscreen to include elements
// that are clipped by their parents in addition to those clipped by
// the rootWebArea.
- // No need to update |offscreen| if |clipped| is not empty, because it
- // should be false by default.
+ // No need to update |offscreen| if |intersection| is not empty, because
+ // it should be false by default.
if (offscreen != nullptr)
*offscreen |= true;
}
@@ -544,7 +544,7 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
if (old_data.state != new_data.state) {
for (int32_t i = static_cast<int32_t>(ax::mojom::State::kNone) + 1;
- i <= static_cast<int32_t>(ax::mojom::State::kLast); ++i) {
+ i <= static_cast<int32_t>(ax::mojom::State::kMaxValue); ++i) {
ax::mojom::State state = static_cast<ax::mojom::State>(i);
if (old_data.HasState(state) != new_data.HasState(state))
delegate_->OnStateChanged(this, node, state, new_data.HasState(state));
diff --git a/chromium/ui/accessibility/ax_tree_serializer.h b/chromium/ui/accessibility/ax_tree_serializer.h
index 098ad4b66a7..b97ad768847 100644
--- a/chromium/ui/accessibility/ax_tree_serializer.h
+++ b/chromium/ui/accessibility/ax_tree_serializer.h
@@ -200,12 +200,14 @@ AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::~AXTreeSerializer() {
template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::Reset() {
client_tree_data_ = AXTreeData();
- if (!client_root_)
- return;
- DeleteClientSubtree(client_root_);
- client_id_map_.erase(client_root_->id);
- delete client_root_;
+ // Normally we use DeleteClientSubtree to remove nodes from the tree,
+ // but Reset() needs to work even if the tree is in a broken state.
+ // Instead, iterate over |client_id_map_| to ensure we clear all nodes and
+ // start from scratch.
+ for (auto&& item : client_id_map_)
+ delete item.second;
+ client_id_map_.clear();
client_root_ = nullptr;
}
@@ -321,10 +323,11 @@ template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
AXSourceNode node,
AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
- // Send the tree data if it's changed since the last update.
+ // 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;
if (tree_->GetTreeData(&new_tree_data) &&
- new_tree_data != client_tree_data_) {
+ (out_update->has_tree_data || new_tree_data != client_tree_data_)) {
out_update->has_tree_data = true;
out_update->tree_data = new_tree_data;
client_tree_data_ = new_tree_data;
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 81d8fb536eb..0bca9825265 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -9,7 +9,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/accessibility/mojom/BUILD.gn b/chromium/ui/accessibility/mojom/BUILD.gn
new file mode 100644
index 00000000000..289e5ca4d01
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ sources = [
+ "ax_node_data.mojom",
+ "ax_tree_data.mojom",
+ "ax_tree_update.mojom",
+ ]
+
+ public_deps = [
+ "//mojo/public/mojom/base",
+ "//ui/accessibility:ax_enums_mojo",
+ "//ui/gfx/geometry/mojo",
+ "//ui/gfx/mojo",
+ ]
+}
diff --git a/chromium/ui/accessibility/mojom/OWNERS b/chromium/ui/accessibility/mojom/OWNERS
new file mode 100644
index 00000000000..ae29a36aac8
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/OWNERS
@@ -0,0 +1,6 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/ui/accessibility/mojom/ax_node_data.mojom b/chromium/ui/accessibility/mojom/ax_node_data.mojom
new file mode 100644
index 00000000000..bbaef03c247
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_node_data.mojom
@@ -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.
+
+module ax.mojom;
+
+import "ui/accessibility/ax_enums.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/transform.mojom";
+
+// See ui::AXNodeData for comments / explanations of these fields.
+struct AXNodeData {
+ int32 id;
+ ax.mojom.Role role;
+ uint32 state;
+ uint32 actions;
+ map<ax.mojom.StringAttribute, string> string_attributes;
+ map<ax.mojom.IntAttribute, int32> int_attributes;
+ map<ax.mojom.FloatAttribute, float> float_attributes;
+ map<ax.mojom.BoolAttribute, bool> bool_attributes;
+ map<ax.mojom.IntListAttribute, array<int32>>
+ intlist_attributes;
+ map<ax.mojom.StringListAttribute, array<string>>
+ stringlist_attributes;
+ map<string, string> html_attributes;
+ array<int32> child_ids;
+ int32 offset_container_id;
+ gfx.mojom.RectF location;
+ gfx.mojom.Transform transform;
+};
diff --git a/chromium/ui/accessibility/mojom/ax_node_data.typemap b/chromium/ui/accessibility/mojom/ax_node_data.typemap
new file mode 100644
index 00000000000..4a36ac29159
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_node_data.typemap
@@ -0,0 +1,19 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//ui/accessibility/mojom/ax_node_data.mojom"
+public_headers = [ "//ui/accessibility/ax_node_data.h" ]
+traits_headers = [ "//ui/accessibility/mojom/ax_node_data_mojom_traits.h" ]
+sources = [
+ "ax_node_data_mojom_traits.cc",
+ "ax_node_data_mojom_traits.h",
+]
+public_deps = [
+ "//ui/accessibility",
+ "//ui/gfx",
+ "//ui/gfx/geometry/mojo",
+ "//ui/gfx/geometry/mojo:struct_traits",
+ "//ui/gfx/mojo",
+]
+type_mappings = [ "ax.mojom.AXNodeData=ui::AXNodeData" ]
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
new file mode 100644
index 00000000000..22873c6b4be
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
@@ -0,0 +1,160 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_node_data_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
+gfx::Transform
+StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::transform(
+ const ui::AXNodeData& p) {
+ if (p.transform)
+ return *p.transform;
+ else
+ return gfx::Transform();
+}
+
+// static
+bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
+ ax::mojom::AXNodeDataDataView data,
+ ui::AXNodeData* out) {
+ out->id = data.id();
+ out->role = data.role();
+ out->state = data.state();
+ out->actions = data.actions();
+
+ std::unordered_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);
+
+ std::unordered_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);
+
+ std::unordered_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);
+
+ std::unordered_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);
+
+ std::unordered_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);
+
+ std::unordered_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);
+
+ std::unordered_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));
+
+ if (!data.ReadChildIds(&out->child_ids))
+ return false;
+
+ out->offset_container_id = data.offset_container_id();
+
+ if (!data.ReadLocation(&out->location))
+ return false;
+
+ gfx::Transform transform;
+ if (!data.ReadTransform(&transform))
+ return false;
+ if (!transform.IsIdentity())
+ out->transform.reset(new gfx::Transform(transform));
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
new file mode 100644
index 00000000000..22c44e975de
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_MOJOM_AX_NODE_DATA_MOJOM_TRAITS_H_
+#define UI_ACCESSIBILITY_MOJOM_AX_NODE_DATA_MOJOM_TRAITS_H_
+
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/mojom/ax_node_data.mojom-shared.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/mojo/transform.mojom.h"
+#include "ui/gfx/mojo/transform_struct_traits.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData> {
+ static int32_t id(const ui::AXNodeData& p) { return p.id; }
+ static ax::mojom::Role role(const ui::AXNodeData& p) { return p.role; }
+ static uint32_t state(const ui::AXNodeData& p) { return p.state; }
+ static uint32_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) {
+ return p.child_ids;
+ }
+ static int32_t offset_container_id(const ui::AXNodeData& p) {
+ return p.offset_container_id;
+ }
+ static gfx::RectF location(const ui::AXNodeData& p) { return p.location; }
+ static gfx::Transform transform(const ui::AXNodeData& p);
+ static bool Read(ax::mojom::AXNodeDataDataView data, ui::AXNodeData* out);
+};
+
+} // namespace mojo
+
+#endif // UI_ACCESSIBILITY_MOJOM_AX_NODE_DATA_MOJOM_TRAITS_H_
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
new file mode 100644
index 00000000000..2e25fdda961
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_node_data_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/mojom/ax_node_data.mojom.h"
+
+using mojo::test::SerializeAndDeserialize;
+
+TEST(AXNodeDataMojomTraitsTest, ID) {
+ ui::AXNodeData input, output;
+ input.id = 42;
+ 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_EQ(ax::mojom::Role::kButton, output.role);
+}
+
+TEST(AXNodeDataMojomTraitsTest, State) {
+ ui::AXNodeData input, output;
+ input.state = 0;
+ input.AddState(ax::mojom::State::kCollapsed);
+ input.AddState(ax::mojom::State::kHorizontal);
+ 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_FALSE(output.HasState(ax::mojom::State::kFocusable));
+ EXPECT_FALSE(output.HasState(ax::mojom::State::kMultiline));
+}
+
+TEST(AXNodeDataMojomTraitsTest, Actions) {
+ ui::AXNodeData input, output;
+ input.actions = 0;
+ input.AddAction(ax::mojom::Action::kDoDefault);
+ input.AddAction(ax::mojom::Action::kDecrement);
+ 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_FALSE(output.HasAction(ax::mojom::Action::kFocus));
+ EXPECT_FALSE(output.HasAction(ax::mojom::Action::kBlur));
+}
+
+TEST(AXNodeDataMojomTraitsTest, StringAttributes) {
+ ui::AXNodeData input, output;
+ input.AddStringAttribute(ax::mojom::StringAttribute::kName, "Mojo");
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ("Mojo",
+ output.GetStringAttribute(ax::mojom::StringAttribute::kName));
+}
+
+TEST(AXNodeDataMojomTraitsTest, IntAttributes) {
+ ui::AXNodeData input, output;
+ input.AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 42);
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ(42, output.GetIntAttribute(ax::mojom::IntAttribute::kScrollX));
+}
+
+TEST(AXNodeDataMojomTraitsTest, FloatAttributes) {
+ ui::AXNodeData input, output;
+ input.AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize, 42);
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ(42, output.GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize));
+}
+
+TEST(AXNodeDataMojomTraitsTest, BoolAttributes) {
+ ui::AXNodeData input, output;
+ input.AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, true);
+ 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_EQ(
+ std::vector<int32_t>({1, 2}),
+ output.GetIntListAttribute(ax::mojom::IntListAttribute::kControlsIds));
+}
+
+TEST(AXNodeDataMojomTraitsTest, StringListAttributes) {
+ ui::AXNodeData input, output;
+ input.AddStringListAttribute(
+ ax::mojom::StringListAttribute::kCustomActionDescriptions,
+ {"foo", "bar"});
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ(std::vector<std::string>({"foo", "bar"}),
+ output.GetStringListAttribute(
+ ax::mojom::StringListAttribute::kCustomActionDescriptions));
+}
+
+TEST(AXNodeDataMojomTraitsTest, ChildIds) {
+ ui::AXNodeData input, output;
+ input.child_ids = {3, 4};
+ 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.offset_container_id = 10;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ(10, output.offset_container_id);
+}
+
+TEST(AXNodeDataMojomTraitsTest, Location) {
+ ui::AXNodeData input, output;
+ input.location = gfx::RectF(1, 2, 3, 4);
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_EQ(1, output.location.x());
+ EXPECT_EQ(2, output.location.y());
+ EXPECT_EQ(3, output.location.width());
+ EXPECT_EQ(4, output.location.height());
+}
+
+TEST(AXNodeDataMojomTraitsTest, Transform) {
+ ui::AXNodeData input, output;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_FALSE(output.transform);
+
+ input.transform = std::make_unique<gfx::Transform>();
+ input.transform->Scale(2.0, 2.0);
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(output.transform);
+ EXPECT_FALSE(output.transform->IsIdentity());
+}
diff --git a/chromium/ui/accessibility/mojom/ax_tree_data.mojom b/chromium/ui/accessibility/mojom/ax_tree_data.mojom
new file mode 100644
index 00000000000..668134576bd
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_data.mojom
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ax.mojom;
+
+import "ui/accessibility/ax_enums.mojom";
+
+// See ui::AXTreeData for comments / explanations of these fields.
+struct AXTreeData {
+ int32 tree_id;
+ int32 parent_tree_id;
+ int32 focused_tree_id;
+ string doctype;
+ bool loaded;
+ float loading_progress;
+ string mimetype;
+ string title;
+ string url;
+ int32 focus_id;
+ int32 sel_anchor_object_id;
+ int32 sel_anchor_offset;
+ ax.mojom.TextAffinity sel_anchor_affinity;
+ int32 sel_focus_object_id;
+ int32 sel_focus_offset;
+ ax.mojom.TextAffinity sel_focus_affinity;
+};
diff --git a/chromium/ui/accessibility/mojom/ax_tree_data.typemap b/chromium/ui/accessibility/mojom/ax_tree_data.typemap
new file mode 100644
index 00000000000..36ca634361e
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_data.typemap
@@ -0,0 +1,15 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//ui/accessibility/mojom/ax_tree_data.mojom"
+public_headers = [ "//ui/accessibility/ax_tree_data.h" ]
+traits_headers = [ "//ui/accessibility/mojom/ax_tree_data_mojom_traits.h" ]
+sources = [
+ "ax_tree_data_mojom_traits.cc",
+ "ax_tree_data_mojom_traits.h",
+]
+public_deps = [
+ "//ui/accessibility",
+]
+type_mappings = [ "ax.mojom.AXTreeData=ui::AXTreeData" ]
diff --git a/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.cc
new file mode 100644
index 00000000000..4c465686e8c
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_tree_data_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<ax::mojom::AXTreeDataDataView, ui::AXTreeData>::Read(
+ ax::mojom::AXTreeDataDataView data,
+ ui::AXTreeData* out) {
+ out->tree_id = data.tree_id();
+ out->parent_tree_id = data.parent_tree_id();
+ out->focused_tree_id = data.focused_tree_id();
+ if (!data.ReadDoctype(&out->doctype))
+ return false;
+ out->loaded = data.loaded();
+ out->loading_progress = data.loading_progress();
+ if (!data.ReadMimetype(&out->mimetype))
+ return false;
+ if (!data.ReadTitle(&out->title))
+ return false;
+ if (!data.ReadUrl(&out->url))
+ return false;
+ out->focus_id = data.focus_id();
+ out->sel_anchor_object_id = data.sel_anchor_object_id();
+ out->sel_anchor_offset = data.sel_anchor_offset();
+ out->sel_anchor_affinity = data.sel_anchor_affinity();
+ out->sel_focus_object_id = data.sel_focus_object_id();
+ out->sel_focus_offset = data.sel_focus_offset();
+ out->sel_focus_affinity = data.sel_focus_affinity();
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.h
new file mode 100644
index 00000000000..0b3a2b138b9
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_MOJOM_AX_TREE_DATA_MOJOM_TRAITS_H_
+#define UI_ACCESSIBILITY_MOJOM_AX_TREE_DATA_MOJOM_TRAITS_H_
+
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/mojom/ax_tree_data.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<ax::mojom::AXTreeDataDataView, ui::AXTreeData> {
+ static int32_t tree_id(const ui::AXTreeData& p) { return p.tree_id; }
+ static int32_t parent_tree_id(const ui::AXTreeData& p) {
+ return p.parent_tree_id;
+ }
+ static int32_t focused_tree_id(const ui::AXTreeData& p) {
+ return p.focused_tree_id;
+ }
+ static std::string doctype(const ui::AXTreeData& p) { return p.doctype; }
+ static bool loaded(const ui::AXTreeData& p) { return p.loaded; }
+ static float loading_progress(const ui::AXTreeData& p) {
+ return p.loading_progress;
+ }
+ static std::string mimetype(const ui::AXTreeData& p) { return p.mimetype; }
+ static std::string title(const ui::AXTreeData& p) { return p.title; }
+ static std::string url(const ui::AXTreeData& p) { return p.url; }
+ static int32_t focus_id(const ui::AXTreeData& p) { return p.focus_id; }
+ static int32_t sel_anchor_object_id(const ui::AXTreeData& p) {
+ return p.sel_anchor_object_id;
+ }
+ static int32_t sel_anchor_offset(const ui::AXTreeData& p) {
+ return p.sel_anchor_offset;
+ }
+ static ax::mojom::TextAffinity sel_anchor_affinity(const ui::AXTreeData& p) {
+ return p.sel_anchor_affinity;
+ }
+ static int32_t sel_focus_object_id(const ui::AXTreeData& p) {
+ return p.sel_focus_object_id;
+ }
+ static int32_t sel_focus_offset(const ui::AXTreeData& p) {
+ return p.sel_focus_offset;
+ }
+ static ax::mojom::TextAffinity sel_focus_affinity(const ui::AXTreeData& p) {
+ return p.sel_focus_affinity;
+ }
+
+ static bool Read(ax::mojom::AXTreeDataDataView data, ui::AXTreeData* out);
+};
+
+} // namespace mojo
+
+#endif // UI_ACCESSIBILITY_MOJOM_AX_TREE_DATA_MOJOM_TRAITS_H_
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
new file mode 100644
index 00000000000..02496fbb001
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_tree_data_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/mojom/ax_tree_data.mojom.h"
+
+using mojo::test::SerializeAndDeserialize;
+
+TEST(AXTreeDataMojomTraitsTest, TestSerializeAndDeserializeAXTreeData) {
+ ui::AXTreeData input, output;
+ input.tree_id = 1;
+ input.parent_tree_id = 2;
+ input.focused_tree_id = 3;
+ input.doctype = "4";
+ input.loaded = true;
+ input.loading_progress = 5;
+ input.mimetype = "6";
+ input.title = "7";
+ input.url = "8";
+ input.focus_id = 9;
+ input.sel_anchor_object_id = 10;
+ input.sel_anchor_offset = 11;
+ input.sel_anchor_affinity = ax::mojom::TextAffinity::kUpstream;
+ input.sel_focus_object_id = 12;
+ input.sel_focus_offset = 13;
+ input.sel_focus_affinity = ax::mojom::TextAffinity::kDownstream;
+
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeData>(&input, &output));
+
+ EXPECT_EQ(1, output.tree_id);
+ EXPECT_EQ(2, output.parent_tree_id);
+ EXPECT_EQ(3, output.focused_tree_id);
+ EXPECT_EQ("4", output.doctype);
+ EXPECT_EQ(true, output.loaded);
+ EXPECT_EQ(5, output.loading_progress);
+ EXPECT_EQ("6", output.mimetype);
+ EXPECT_EQ("7", output.title);
+ EXPECT_EQ("8", output.url);
+ EXPECT_EQ(9, output.focus_id);
+ EXPECT_EQ(10, output.sel_anchor_object_id);
+ EXPECT_EQ(11, output.sel_anchor_offset);
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, output.sel_anchor_affinity);
+ EXPECT_EQ(12, output.sel_focus_object_id);
+ EXPECT_EQ(13, output.sel_focus_offset);
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, output.sel_focus_affinity);
+}
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update.mojom b/chromium/ui/accessibility/mojom/ax_tree_update.mojom
new file mode 100644
index 00000000000..b121cd6c66f
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_update.mojom
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ax.mojom;
+
+import "ui/accessibility/ax_enums.mojom";
+import "ui/accessibility/mojom/ax_node_data.mojom";
+import "ui/accessibility/mojom/ax_tree_data.mojom";
+
+// See ui::AXTreeUpdate for comments / explanations of these fields.
+struct AXTreeUpdate {
+ bool has_tree_data;
+ AXTreeData tree_data;
+ int32 node_id_to_clear;
+ int32 root_id;
+ array<AXNodeData> nodes;
+};
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update.typemap b/chromium/ui/accessibility/mojom/ax_tree_update.typemap
new file mode 100644
index 00000000000..0fa557951e4
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_update.typemap
@@ -0,0 +1,15 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//ui/accessibility/mojom/ax_tree_update.mojom"
+public_headers = [ "//ui/accessibility/ax_tree_update.h" ]
+traits_headers = [ "//ui/accessibility/mojom/ax_tree_update_mojom_traits.h" ]
+sources = [
+ "ax_tree_update_mojom_traits.cc",
+ "ax_tree_update_mojom_traits.h",
+]
+public_deps = [
+ "//ui/accessibility",
+]
+type_mappings = [ "ax.mojom.AXTreeUpdate=ui::AXTreeUpdate" ]
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc
new file mode 100644
index 00000000000..c3f29453c86
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_tree_update_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<ax::mojom::AXTreeUpdateDataView, ui::AXTreeUpdate>::Read(
+ ax::mojom::AXTreeUpdateDataView data,
+ ui::AXTreeUpdate* out) {
+ out->has_tree_data = data.has_tree_data();
+ if (!data.ReadTreeData(&out->tree_data))
+ return false;
+ out->node_id_to_clear = data.node_id_to_clear();
+ out->root_id = data.root_id();
+ if (!data.ReadNodes(&out->nodes))
+ return false;
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h
new file mode 100644
index 00000000000..90718e3b849
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_MOJOM_AX_TREE_UPDATE_MOJOM_TRAITS_H_
+#define UI_ACCESSIBILITY_MOJOM_AX_TREE_UPDATE_MOJOM_TRAITS_H_
+
+#include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/mojom/ax_node_data_mojom_traits.h"
+#include "ui/accessibility/mojom/ax_tree_data_mojom_traits.h"
+#include "ui/accessibility/mojom/ax_tree_update.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<ax::mojom::AXTreeUpdateDataView, ui::AXTreeUpdate> {
+ static bool has_tree_data(const ui::AXTreeUpdate& p) {
+ return p.has_tree_data;
+ }
+ static ui::AXTreeData tree_data(const ui::AXTreeUpdate& p) {
+ return p.tree_data;
+ }
+ static int32_t node_id_to_clear(const ui::AXTreeUpdate& p) {
+ return p.node_id_to_clear;
+ }
+ static int32_t root_id(const ui::AXTreeUpdate& p) { return p.root_id; }
+ static std::vector<ui::AXNodeData> nodes(const ui::AXTreeUpdate& p) {
+ return p.nodes;
+ }
+
+ static bool Read(ax::mojom::AXTreeUpdateDataView data, ui::AXTreeUpdate* out);
+};
+
+} // namespace mojo
+
+#endif // UI_ACCESSIBILITY_MOJOM_AX_TREE_UPDATE_MOJOM_TRAITS_H_
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
new file mode 100644
index 00000000000..49b3d262be8
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/mojom/ax_tree_update_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/mojom/ax_tree_update.mojom.h"
+
+using mojo::test::SerializeAndDeserialize;
+
+TEST(AXTreeUpdateMojomTraitsTest, TestSerializeAndDeserializeAXTreeUpdate) {
+ ui::AXTreeUpdate input, output;
+ input.has_tree_data = true;
+ input.tree_data.focus_id = 1;
+ input.node_id_to_clear = 2;
+ input.root_id = 3;
+ input.nodes.resize(2);
+ input.nodes[0].role = ax::mojom::Role::kButton;
+ input.nodes[1].id = 4;
+ 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);
+ EXPECT_EQ(3, output.root_id);
+ ASSERT_EQ(2U, output.nodes.size());
+ EXPECT_EQ(ax::mojom::Role::kButton, output.nodes[0].role);
+ EXPECT_EQ(4, output.nodes[1].id);
+}
diff --git a/chromium/ui/accessibility/mojom/typemaps.gni b/chromium/ui/accessibility/mojom/typemaps.gni
new file mode 100644
index 00000000000..019293d4809
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/typemaps.gni
@@ -0,0 +1,9 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+typemaps = [
+ "//ui/accessibility/mojom/ax_node_data.typemap",
+ "//ui/accessibility/mojom/ax_tree_data.typemap",
+ "//ui/accessibility/mojom/ax_tree_update.typemap",
+]
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.cc b/chromium/ui/accessibility/platform/ax_platform_node.cc
index f0f00d69bd1..8522f21599e 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node.cc
@@ -22,6 +22,9 @@ base::LazyInstance<AXPlatformNode::NativeWindowHandlerCallback>::Leaky
AXPlatformNode::native_window_handler_ = LAZY_INSTANCE_INITIALIZER;
// static
+bool AXPlatformNode::is_autofill_shown_ = false;
+
+// static
AXPlatformNode* AXPlatformNode::FromNativeWindow(
gfx::NativeWindow native_window) {
if (native_window_handler_.Get())
@@ -72,4 +75,19 @@ void AXPlatformNode::NotifyAddAXModeFlags(AXMode mode_flags) {
observer.OnAXModeAdded(mode_flags);
}
+// static
+void AXPlatformNode::OnAutofillShown() {
+ is_autofill_shown_ = true;
+}
+
+// static
+void AXPlatformNode::OnAutofillHidden() {
+ is_autofill_shown_ = false;
+}
+
+// static
+bool AXPlatformNode::IsAutofillShown() {
+ return is_autofill_shown_;
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.h b/chromium/ui/accessibility/platform/ax_platform_node.h
index f723bf064c4..95d38c7288d 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node.h
@@ -53,6 +53,10 @@ class AX_EXPORT AXPlatformNode {
// the addition of an AXMode flag.
static void NotifyAddAXModeFlags(AXMode mode_flags);
+ static void OnAutofillShown();
+ static void OnAutofillHidden();
+ static bool IsAutofillShown();
+
// Call Destroy rather than deleting this, because the subclass may
// use reference counting.
virtual void Destroy();
@@ -84,6 +88,8 @@ class AX_EXPORT AXPlatformNode {
static base::LazyInstance<NativeWindowHandlerCallback>::Leaky
native_window_handler_;
+ static bool is_autofill_shown_;
+
DISALLOW_COPY_AND_ASSIGN(AXPlatformNode);
};
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
index b502a6786c6..b73cd96f754 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -986,9 +986,9 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
atk_state_set_add_state(atk_state_set, ATK_STATE_HAS_POPUP);
#endif
#endif
- if (data.HasState(ax::mojom::State::kSelected))
+ if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTED);
- if (data.HasState(ax::mojom::State::kSelectable))
+ if (data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE);
// Checked state
@@ -1113,6 +1113,7 @@ void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
ax::mojom::Event event_type) {
switch (event_type) {
case ax::mojom::Event::kFocus:
+ case ax::mojom::Event::kFocusContext:
OnFocused();
break;
default:
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.h b/chromium/ui/accessibility/platform/ax_platform_node_base.h
index 2525833c6c0..3b308c716f5 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.h
@@ -134,6 +134,8 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// that might send notifications.
bool IsLeaf();
+ bool HasFocus();
+
virtual base::string16 GetText();
virtual base::string16 GetValue();
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
index 6a439f162f8..6c12a5cb164 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -200,6 +200,8 @@ EventMap BuildEventMap() {
const EventMap::value_type events[] = {
{ax::mojom::Event::kFocus,
NSAccessibilityFocusedUIElementChangedNotification},
+ {ax::mojom::Event::kFocusContext,
+ NSAccessibilityFocusedUIElementChangedNotification},
{ax::mojom::Event::kTextChanged, NSAccessibilityTitleChangedNotification},
{ax::mojom::Event::kValueChanged,
NSAccessibilityValueChangedNotification},
@@ -514,7 +516,8 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
// Since tabs use the Radio Button role on Mac, the standard way to set
// them is via the value attribute rather than the selected attribute.
if (node_->GetData().role == ax::mojom::Role::kTab)
- return !node_->GetData().HasState(ax::mojom::State::kSelected);
+ return !node_->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected);
return restriction != ax::mojom::Restriction::kReadOnly;
}
@@ -719,7 +722,8 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
// Misc attributes.
- (NSNumber*)AXSelected {
- return @(node_->GetData().HasState(ax::mojom::State::kSelected));
+ return
+ @(node_->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
}
- (NSString*)AXPlaceholderValue {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
index 9cb8b4428a3..29a5404d084 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
@@ -74,7 +74,7 @@ AXTreeUpdate AXPlatformNodeTest::BuildTextFieldWithSelectionRange(
text_field_node.id = 1;
text_field_node.role = ax::mojom::Role::kTextField;
text_field_node.AddState(ax::mojom::State::kEditable);
- text_field_node.AddState(ax::mojom::State::kSelected);
+ text_field_node.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
text_field_node.AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
start);
text_field_node.AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, stop);
@@ -108,7 +108,8 @@ AXTreeUpdate AXPlatformNodeTest::BuildContentEditableWithSelectionRange(
content_editable_node.id = 1;
content_editable_node.role = ax::mojom::Role::kGroup;
content_editable_node.AddState(ax::mojom::State::kRichlyEditable);
- content_editable_node.AddState(ax::mojom::State::kSelected);
+ content_editable_node.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+ true);
content_editable_node.AddBoolAttribute(
ax::mojom::BoolAttribute::kEditableRoot, true);
content_editable_node.SetValue("How now brown cow.");
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index f266a181e11..8a0e88b2ecb 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -347,9 +347,17 @@ void AXPlatformNodeWin::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
// Menu items fire selection events but Windows screen readers work reliably
// with focus events. Remap here.
- if (event_type == ax::mojom::Event::kSelection &&
- GetData().role == ax::mojom::Role::kMenuItem)
- event_type = ax::mojom::Event::kFocus;
+ if (event_type == ax::mojom::Event::kSelection) {
+ // A menu item could have something other than a role of
+ // |ROLE_SYSTEM_MENUITEM|. Zoom modification controls for example have a
+ // role of button.
+ auto* parent =
+ static_cast<AXPlatformNodeWin*>(FromNativeViewAccessible(GetParent()));
+ if (MSAARole() == ROLE_SYSTEM_MENUITEM ||
+ (parent && parent->MSAARole() == ROLE_SYSTEM_MENUPOPUP)) {
+ event_type = ax::mojom::Event::kFocus;
+ }
+ }
int native_event = MSAAEvent(event_type);
if (native_event < EVENT_MIN)
@@ -844,7 +852,8 @@ STDMETHODIMP AXPlatformNodeWin::get_accSelection(VARIANT* selected) {
for (int i = 0; i < delegate_->GetChildCount(); ++i) {
auto* node = static_cast<AXPlatformNodeWin*>(
FromNativeViewAccessible(delegate_->ChildAtIndex(i)));
- if (node && node->GetData().HasState(ax::mojom::State::kSelected))
+ if (node &&
+ node->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
selected_nodes.emplace_back(node);
}
@@ -1440,7 +1449,8 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedChildren(LONG* cell_count) {
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < columns; ++c) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (cell && cell->GetData().HasState(ax::mojom::State::kSelected))
+ if (cell &&
+ cell->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
result++;
}
}
@@ -1467,7 +1477,8 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedColumns(LONG* column_count) {
bool selected = true;
for (int r = 0; r < rows && selected == true; ++r) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
selected = false;
}
if (selected)
@@ -1497,7 +1508,8 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedRows(LONG* row_count) {
bool selected = true;
for (int c = 0; c < columns && selected == true; ++c) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
selected = false;
}
if (selected)
@@ -1607,7 +1619,8 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedChildren(LONG max_children,
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < columns; ++c) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (cell && cell->GetData().HasState(ax::mojom::State::kSelected))
+ if (cell &&
+ cell->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
// index is row index * column count + column index.
results.push_back(r * columns + c);
}
@@ -1636,7 +1649,8 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedColumns(LONG max_columns,
bool selected = true;
for (int r = 0; r < row_count && selected == true; ++r) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
selected = false;
}
if (selected)
@@ -1664,7 +1678,8 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedRows(LONG max_rows,
bool selected = true;
for (int c = 0; c < column_count && selected == true; ++c) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
selected = false;
}
if (selected)
@@ -1701,7 +1716,8 @@ STDMETHODIMP AXPlatformNodeWin::get_isColumnSelected(LONG column,
for (int r = 0; r < rows; ++r) {
AXPlatformNodeBase* cell = GetTableCell(r, column);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
return S_OK;
}
@@ -1724,7 +1740,8 @@ STDMETHODIMP AXPlatformNodeWin::get_isRowSelected(LONG row,
for (int c = 0; c < columns; ++c) {
AXPlatformNodeBase* cell = GetTableCell(row, c);
- if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected)))
+ if (!cell || !(cell->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)))
return S_OK;
}
@@ -1748,7 +1765,8 @@ STDMETHODIMP AXPlatformNodeWin::get_isSelected(LONG row,
return S_FALSE;
AXPlatformNodeBase* cell = GetTableCell(row, column);
- if (cell && cell->GetData().HasState(ax::mojom::State::kSelected))
+ if (cell &&
+ cell->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
*is_selected = true;
return S_OK;
@@ -1865,7 +1883,8 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedCells(IUnknown*** cells,
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < columns; ++c) {
AXPlatformNodeBase* cell = GetTableCell(r, c);
- if (cell && cell->GetData().HasState(ax::mojom::State::kSelected))
+ if (cell &&
+ cell->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
selected.push_back(cell);
}
}
@@ -2411,7 +2430,10 @@ int AXPlatformNodeWin::MSAARole() {
return ROLE_SYSTEM_ALERT;
case ax::mojom::Role::kAlertDialog:
- return ROLE_SYSTEM_DIALOG;
+ // We temporarily use |ROLE_SYSTEM_ALERT| because some Windows screen
+ // readers are not compatible with |ax::mojom::Role::kAlertDialog| yet.
+ // TODO(aleventhal) modify this to return |ROLE_SYSTEM_DIALOG|.
+ return ROLE_SYSTEM_ALERT;
case ax::mojom::Role::kAnchor:
return ROLE_SYSTEM_LINK;
@@ -2859,8 +2881,10 @@ int32_t AXPlatformNodeWin::ComputeIA2State() {
ia2_state |= IA2_STATE_SELECTABLE_TEXT;
}
- if (!GetStringAttribute(ax::mojom::StringAttribute::kAutoComplete).empty())
+ if (!GetStringAttribute(ax::mojom::StringAttribute::kAutoComplete).empty() ||
+ IsAutofillField()) {
ia2_state |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
+ }
if (GetBoolAttribute(ax::mojom::BoolAttribute::kModal))
ia2_state |= IA2_STATE_MODAL;
@@ -3024,6 +3048,11 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() {
StringAttributeToIA2(result, ax::mojom::StringAttribute::kAutoComplete,
"autocomplete");
+ if (!HasStringAttribute(ax::mojom::StringAttribute::kAutoComplete) &&
+ IsAutofillField()) {
+ result.push_back(L"autocomplete:list");
+ }
+
StringAttributeToIA2(result, ax::mojom::StringAttribute::kRoleDescription,
"roledescription");
StringAttributeToIA2(result, ax::mojom::StringAttribute::kKeyShortcuts,
@@ -3375,7 +3404,7 @@ bool AXPlatformNodeWin::ShouldNodeHaveFocusableState(
case ax::mojom::Role::kListBoxOption:
case ax::mojom::Role::kMenuListOption:
- if (data.HasState(ax::mojom::State::kSelectable))
+ if (data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
return true;
break;
@@ -3386,6 +3415,11 @@ bool AXPlatformNodeWin::ShouldNodeHaveFocusableState(
return data.HasState(ax::mojom::State::kFocusable);
}
+bool AXPlatformNodeWin::IsAutofillField() {
+ return IsAutofillShown() && IsPlainTextField() &&
+ delegate_->GetFocus() == GetNativeViewAccessible();
+}
+
int AXPlatformNodeWin::MSAAState() {
const AXNodeData& data = GetData();
int msaa_state = 0;
@@ -3410,7 +3444,9 @@ int AXPlatformNodeWin::MSAAState() {
if (ShouldNodeHaveFocusableState(data))
msaa_state |= STATE_SYSTEM_FOCUSABLE;
- if (data.HasState(ax::mojom::State::kHaspopup))
+ // Note: autofill is special-cased here because there is no way for the
+ // browser to know when the autofill popup is shown.
+ if (data.HasState(ax::mojom::State::kHaspopup) || IsAutofillField())
msaa_state |= STATE_SYSTEM_HASPOPUP;
// TODO(dougt) unhandled ux::ax::mojom::State::kHorizontal
@@ -3448,10 +3484,10 @@ int AXPlatformNodeWin::MSAAState() {
// TODO(dougt) unhandled ux::ax::mojom::State::kRequired
// TODO(dougt) unhandled ux::ax::mojom::State::kRichlyEditable
- if (data.HasState(ax::mojom::State::kSelectable))
+ if (data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
msaa_state |= STATE_SYSTEM_SELECTABLE;
- if (data.HasState(ax::mojom::State::kSelected))
+ if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
msaa_state |= STATE_SYSTEM_SELECTED;
// TODO(dougt) unhandled VERTICAL
@@ -3504,6 +3540,22 @@ int AXPlatformNodeWin::MSAAState() {
if (focus == GetNativeViewAccessible())
msaa_state |= STATE_SYSTEM_FOCUSED;
+ // In focused single selection UI menus and listboxes, mirror item selection
+ // to focus. This helps NVDA read the selected option as it changes.
+ if ((data.role == ax::mojom::Role::kListBoxOption ||
+ data.role == ax::mojom::Role::kMenuItem) &&
+ data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
+ AXPlatformNodeBase* container = FromNativeViewAccessible(GetParent());
+ if (container && container->GetParent() == focus) {
+ ui::AXNodeData container_data = container->GetData();
+ if ((container_data.role == ax::mojom::Role::kListBox ||
+ container_data.role == ax::mojom::Role::kMenu) &&
+ !container_data.HasState(ax::mojom::State::kMultiselectable)) {
+ msaa_state |= STATE_SYSTEM_FOCUSED;
+ }
+ }
+ }
+
// On Windows, the "focus" bit should be set on certain containers, like
// menu bars, when visible.
//
@@ -3534,7 +3586,10 @@ int AXPlatformNodeWin::MSAAEvent(ax::mojom::Event event) {
case ax::mojom::Event::kExpandedChanged:
return EVENT_OBJECT_STATECHANGE;
case ax::mojom::Event::kFocus:
+ case ax::mojom::Event::kFocusContext:
return EVENT_OBJECT_FOCUS;
+ case ax::mojom::Event::kLiveRegionChanged:
+ return EVENT_OBJECT_LIVEREGIONCHANGED;
case ax::mojom::Event::kMenuStart:
return EVENT_SYSTEM_MENUSTART;
case ax::mojom::Event::kMenuEnd:
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h
index 4efab44077a..b9177015b47 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h
@@ -775,6 +775,8 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
bool IsAncestorComboBox();
+ // Is in a focused texfield with a related autofill popup currently visible.
+ bool IsAutofillField();
};
} // namespace ui
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 20de83957ca..ac24063a4f9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -295,7 +295,7 @@ TEST_F(AXPlatformNodeWinTest,
AXNodeData list_item_1;
list_item_1.id = 1;
list_item_1.role = ax::mojom::Role::kListBoxOption;
- list_item_1.AddState(ax::mojom::State::kSelected);
+ list_item_1.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_1.SetName("Name1");
AXNodeData list_item_2;
@@ -327,13 +327,13 @@ TEST_F(AXPlatformNodeWinTest,
AXNodeData list_item_1;
list_item_1.id = 1;
list_item_1.role = ax::mojom::Role::kListBoxOption;
- list_item_1.AddState(ax::mojom::State::kSelected);
+ list_item_1.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_1.SetName("Name1");
AXNodeData list_item_2;
list_item_2.id = 2;
list_item_2.role = ax::mojom::Role::kListBoxOption;
- list_item_2.AddState(ax::mojom::State::kSelected);
+ list_item_2.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_2.SetName("Name2");
AXNodeData list_item_3;
@@ -415,7 +415,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionTableRowOneSelected) {
AXTreeUpdate update = Build3X3Table();
// 5 == table_row_1
- update.nodes[5].AddState(ax::mojom::State::kSelected);
+ update.nodes[5].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -443,8 +443,8 @@ TEST_F(AXPlatformNodeWinTest,
// 5 == table_row_1
// 9 == table_row_2
- update.nodes[5].AddState(ax::mojom::State::kSelected);
- update.nodes[9].AddState(ax::mojom::State::kSelected);
+ update.nodes[5].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[9].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -505,7 +505,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionTableCellOneSelected) {
AXTreeUpdate update = Build3X3Table();
// 7 == table_cell_1
- update.nodes[7].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -543,8 +543,8 @@ TEST_F(AXPlatformNodeWinTest,
// 11 == table_cell_3
// 12 == table_cell_4
- update.nodes[11].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1647,7 +1647,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedChildrenOne) {
AXTreeUpdate update = Build3X3Table();
// 7 == table_cell_1
- update.nodes[7].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
ComPtr<IAccessibleTableCell> cell = GetCellInTable();
@@ -1672,10 +1672,10 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedChildrenMany) {
// 8 == table_cell_2
// 11 == table_cell_3
// 12 == table_cell_4
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1718,9 +1718,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedColumnsOne) {
// 3 == table_column_header_2
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[3].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1745,16 +1745,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedColumnsMany) {
// 3 == table_column_header_2
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[3].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
// 4 == table_column_header_3
// 8 == table_cell_2
// 12 == table_cell_4
- update.nodes[4].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[4].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1797,9 +1797,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedRowsOne) {
// 6 == table_row_header_1
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1824,16 +1824,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedRowsMany) {
// 6 == table_row_header_3
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
// 10 == table_row_header_3
// 11 == table_cell_1
// 12 == table_cell_2
- update.nodes[10].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[10].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1857,8 +1857,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedChildren) {
// 7 == table_cell_1
// 12 == table_cell_4
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1886,8 +1886,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedChildrenZeroMax) {
// 7 == table_cell_1
// 12 == table_cell_4
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1911,8 +1911,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsZero) {
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1940,9 +1940,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsOne) {
// 3 == table_column_header_2
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[3].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -1971,16 +1971,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsMany) {
// 3 == table_column_header_2
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[3].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
// 4 == table_column_header_3
// 8 == table_cell_2
// 12 == table_cell_4
- update.nodes[4].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[4].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2030,9 +2030,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedRowsOne) {
// 6 == table_row_header_1
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2060,16 +2060,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedRowsMany) {
// 6 == table_row_header_3
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
// 10 == table_row_header_3
// 11 == table_cell_1
// 12 == table_cell_2
- update.nodes[10].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[10].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2098,9 +2098,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsColumnSelected) {
// 3 == table_column_header_2
// 7 == table_cell_1
// 11 == table_cell_3
- update.nodes[3].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[11].AddState(ax::mojom::State::kSelected);
+ update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2134,9 +2134,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsRowSelected) {
// 6 == table_row_header_3
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2170,9 +2170,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsSelected) {
// 6 == table_row_header_3
// 7 == table_cell_1
// 8 == table_cell_2
- update.nodes[6].AddState(ax::mojom::State::kSelected);
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[8].AddState(ax::mojom::State::kSelected);
+ update.nodes[6].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[8].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
@@ -2235,8 +2235,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTable2GetSelectedChildren) {
// 7 == table_cell_1
// 12 == table_cell_4
- update.nodes[7].AddState(ax::mojom::State::kSelected);
- update.nodes[12].AddState(ax::mojom::State::kSelected);
+ update.nodes[7].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+ update.nodes[12].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
Init(update);
diff --git a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
index 803fc97e4d8..8c3402e7417 100644
--- a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
@@ -122,7 +122,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
if (first_time) {
for (int32_t attr_index =
static_cast<int32_t>(ax::mojom::IntAttribute::kNone);
- attr_index <= static_cast<int32_t>(ax::mojom::IntAttribute::kLast);
+ attr_index <= static_cast<int32_t>(ax::mojom::IntAttribute::kMaxValue);
++attr_index) {
auto attr = static_cast<ax::mojom::IntAttribute>(attr_index);
if (!GetIA2ReverseRelationFromIntAttr(attr).empty())
@@ -130,7 +130,8 @@ int AXPlatformRelationWin::EnumerateRelationships(
}
for (int32_t attr_index =
static_cast<int32_t>(ax::mojom::IntListAttribute::kNone);
- attr_index <= static_cast<int32_t>(ax::mojom::IntListAttribute::kLast);
+ attr_index <=
+ static_cast<int32_t>(ax::mojom::IntListAttribute::kMaxValue);
++attr_index) {
auto attr = static_cast<ax::mojom::IntListAttribute>(attr_index);
if (!GetIA2ReverseRelationFromIntListAttr(attr).empty())
diff --git a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc
index 998ae65757c..7ef8a5c6689 100644
--- a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc
+++ b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc
@@ -7,7 +7,6 @@
#include <string>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chromium/ui/accessibility/run_all_unittests.cc b/chromium/ui/accessibility/run_all_unittests.cc
new file mode 100644
index 00000000000..3cdbe276dd9
--- /dev/null
+++ b/chromium/ui/accessibility/run_all_unittests.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+#include "mojo/edk/embedder/embedder.h"
+
+int main(int argc, char** argv) {
+ mojo::edk::Init();
+
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/ui/android/BUILD.gn b/chromium/ui/android/BUILD.gn
index a9196e95dc7..4002626c015 100644
--- a/chromium/ui/android/BUILD.gn
+++ b/chromium/ui/android/BUILD.gn
@@ -63,7 +63,7 @@ component("android") {
"//components/viz/service",
"//services/viz/public/interfaces",
"//skia",
- "//third_party/WebKit/public:blink_headers",
+ "//third_party/blink/public:blink_headers",
"//ui/base",
"//ui/compositor",
"//ui/display",
@@ -197,16 +197,21 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/DropdownDividerDrawable.java",
"java/src/org/chromium/ui/DropdownItem.java",
"java/src/org/chromium/ui/DropdownItemBase.java",
+ "java/src/org/chromium/ui/DropdownPopupWindowImpl.java",
"java/src/org/chromium/ui/DropdownPopupWindow.java",
+ "java/src/org/chromium/ui/DropdownPopupWindowJellyBean.java",
+ "java/src/org/chromium/ui/DropdownPopupWindowInterface.java",
"java/src/org/chromium/ui/HorizontalListDividerDrawable.java",
"java/src/org/chromium/ui/OverscrollRefreshHandler.java",
"java/src/org/chromium/ui/VSyncMonitor.java",
+ "java/src/org/chromium/ui/base/ActivityAndroidPermissionDelegate.java",
"java/src/org/chromium/ui/base/ActivityWindowAndroid.java",
"java/src/org/chromium/ui/base/AndroidPermissionDelegate.java",
"java/src/org/chromium/ui/base/Clipboard.java",
"java/src/org/chromium/ui/base/DeviceFormFactor.java",
"java/src/org/chromium/ui/base/EventForwarder.java",
"java/src/org/chromium/ui/base/LocalizationUtils.java",
+ "java/src/org/chromium/ui/base/PermissionCallback.java",
"java/src/org/chromium/ui/base/ResourceBundle.java",
"java/src/org/chromium/ui/base/SelectFileDialog.java",
"java/src/org/chromium/ui/base/SPenSupport.java",
@@ -217,6 +222,7 @@ android_library("ui_full_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",
+ "java/src/org/chromium/ui/display/DisplayUtil.java",
"java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java",
"java/src/org/chromium/ui/display/VirtualDisplayAndroid.java",
"java/src/org/chromium/ui/events/devices/InputDeviceObserver.java",
@@ -248,6 +254,7 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java",
"java/src/org/chromium/ui/widget/TextViewWithLeading.java",
"java/src/org/chromium/ui/widget/Toast.java",
+ "java/src/org/chromium/ui/widget/UiWidgetFactory.java",
"java/src/org/chromium/ui/widget/ViewRectProvider.java",
]
deps = [
@@ -259,7 +266,7 @@ android_library("ui_full_java") {
]
srcjar_deps = [
":java_enums_srcjar",
- "//third_party/WebKit/public:blink_cursor_type_java_enums_srcjar",
+ "//third_party/blink/public:blink_cursor_type_java_enums_srcjar",
]
}
@@ -295,6 +302,7 @@ junit_binary("ui_junit_tests") {
test("ui_android_unittests") {
sources = [
+ "delegated_frame_host_android_unittest.cc",
"overscroll_refresh_unittest.cc",
"resources/resource_manager_impl_unittest.cc",
"run_all_unittests.cc",
@@ -308,10 +316,13 @@ test("ui_android_unittests") {
"//base/test:test_support",
"//cc",
"//cc:test_support",
+ "//components/viz/host:host",
+ "//components/viz/service:service",
"//skia",
"//testing/gmock",
"//testing/gtest",
"//ui/base",
+ "//ui/compositor",
"//ui/events",
"//ui/gfx",
"//ui/resources:ui_test_pak",
diff --git a/chromium/ui/android/DEPS b/chromium/ui/android/DEPS
index 6f43de66845..bfdcf7553b2 100644
--- a/chromium/ui/android/DEPS
+++ b/chromium/ui/android/DEPS
@@ -13,7 +13,7 @@ include_rules = [
"+jni",
"+services/viz/public/interfaces",
"+skia/ext",
- "+third_party/WebKit/public/platform/WebCursorInfo.h",
+ "+third_party/blink/public/platform/web_cursor_info.h",
"+third_party/skia",
"+ui/base",
"+ui/compositor/compositor_lock.h",
diff --git a/chromium/ui/android/delegated_frame_host_android.cc b/chromium/ui/android/delegated_frame_host_android.cc
index 07798eaf868..cea1307c5eb 100644
--- a/chromium/ui/android/delegated_frame_host_android.cc
+++ b/chromium/ui/android/delegated_frame_host_android.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/surface_layer.h"
#include "components/viz/common/features.h"
@@ -27,16 +26,18 @@ namespace ui {
namespace {
scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer(
- viz::SurfaceInfo surface_info,
+ const viz::SurfaceId& surface_id,
+ const gfx::Size& size_in_pixels,
bool surface_opaque) {
// manager must outlive compositors using it.
auto layer = cc::SurfaceLayer::Create();
- layer->SetPrimarySurfaceId(surface_info.id(),
+ layer->SetPrimarySurfaceId(surface_id,
cc::DeadlinePolicy::UseDefaultDeadline());
- layer->SetFallbackSurfaceId(surface_info.id());
- layer->SetBounds(surface_info.size_in_pixels());
+ layer->SetFallbackSurfaceId(surface_id);
+ layer->SetBounds(size_in_pixels);
layer->SetIsDrawable(true);
layer->SetContentsOpaque(surface_opaque);
+ layer->SetHitTestable(true);
return layer;
}
@@ -89,7 +90,8 @@ void DelegatedFrameHostAndroid::SubmitCompositorFrame(
std::move(hit_test_region_list));
content_layer_ =
- CreateSurfaceLayer(surface_info_, !has_transparent_background_);
+ CreateSurfaceLayer(surface_info_.id(), surface_info_.size_in_pixels(),
+ !has_transparent_background_);
view_->GetLayer()->AddChild(content_layer_);
} else {
support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
@@ -111,27 +113,28 @@ void DelegatedFrameHostAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
+ // TODO(vmpstr): We should defer this request until such time that this
+ // returns true. https://crbug.com/826097.
if (!CanCopyFromCompositingSurface()) {
std::move(callback).Run(SkBitmap());
return;
}
- scoped_refptr<cc::Layer> readback_layer =
- CreateSurfaceLayer(surface_info_, !has_transparent_background_);
- readback_layer->SetHideLayerAndSubtree(true);
- view_->GetWindowAndroid()->GetCompositor()->AttachLayerForReadback(
- readback_layer);
+ WindowAndroidCompositor* compositor =
+ view_->GetWindowAndroid()->GetCompositor();
+ compositor->IncrementReadbackRequestCount();
std::unique_ptr<viz::CopyOutputRequest> request =
std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(
[](base::OnceCallback<void(const SkBitmap&)> callback,
- scoped_refptr<cc::Layer> readback_layer,
+ base::WeakPtr<WindowAndroidCompositor> compositor_weak_ptr,
std::unique_ptr<viz::CopyOutputResult> result) {
- readback_layer->RemoveFromParent();
+ if (compositor_weak_ptr)
+ compositor_weak_ptr->DecrementReadbackRequestCount();
std::move(callback).Run(result->AsSkBitmap());
},
- std::move(callback), std::move(readback_layer)));
+ std::move(callback), compositor->GetWeakPtr()));
if (src_subrect.IsEmpty()) {
request->set_area(gfx::Rect(surface_info_.size_in_pixels()));
@@ -147,7 +150,7 @@ void DelegatedFrameHostAndroid::CopyFromCompositingSurface(
gfx::Vector2d(output_size.width(), output_size.height()));
}
- support_->RequestCopyOfSurface(std::move(request));
+ support_->RequestCopyOfOutput(local_surface_id_, std::move(request));
}
bool DelegatedFrameHostAndroid::CanCopyFromCompositingSurface() const {
@@ -156,15 +159,17 @@ bool DelegatedFrameHostAndroid::CanCopyFromCompositingSurface() const {
}
void DelegatedFrameHostAndroid::DestroyDelegatedContent() {
- if (!surface_info_.is_valid())
- return;
-
- DCHECK(content_layer_);
+ // TakeFallbackContentFrom() can populate |content_layer_| when
+ // |surface_info_| is invalid.
+ if (content_layer_) {
+ content_layer_->RemoveFromParent();
+ content_layer_ = nullptr;
+ }
- content_layer_->RemoveFromParent();
- content_layer_ = nullptr;
- support_->EvictLastActivatedSurface();
- surface_info_ = viz::SurfaceInfo();
+ if (surface_info_.is_valid()) {
+ support_->EvictLastActivatedSurface();
+ surface_info_ = viz::SurfaceInfo();
+ }
}
bool DelegatedFrameHostAndroid::HasDelegatedContent() const {
@@ -228,10 +233,14 @@ void DelegatedFrameHostAndroid::DidPresentCompositorFrame(
uint32_t presentation_token,
base::TimeTicks time,
base::TimeDelta refresh,
- uint32_t flags) {}
+ uint32_t flags) {
+ client_->DidPresentCompositorFrame(presentation_token, time, refresh, flags);
+}
void DelegatedFrameHostAndroid::DidDiscardCompositorFrame(
- uint32_t presentation_token) {}
+ uint32_t presentation_token) {
+ client_->DidDiscardCompositorFrame(presentation_token);
+}
void DelegatedFrameHostAndroid::OnBeginFrame(const viz::BeginFrameArgs& args) {
begin_frame_source_.OnBeginFrame(args);
@@ -279,4 +288,15 @@ const viz::LocalSurfaceId& DelegatedFrameHostAndroid::GetLocalSurfaceId()
return local_surface_id_;
}
+void DelegatedFrameHostAndroid::TakeFallbackContentFrom(
+ DelegatedFrameHostAndroid* other) {
+ if (content_layer_ || !other->content_layer_)
+ return;
+ content_layer_ =
+ CreateSurfaceLayer(other->content_layer_->fallback_surface_id(),
+ other->content_layer_->bounds(),
+ other->content_layer_->contents_opaque());
+ view_->GetLayer()->AddChild(content_layer_);
+}
+
} // namespace ui
diff --git a/chromium/ui/android/delegated_frame_host_android.h b/chromium/ui/android/delegated_frame_host_android.h
index c0fbac92d08..b0fed79e73e 100644
--- a/chromium/ui/android/delegated_frame_host_android.h
+++ b/chromium/ui/android/delegated_frame_host_android.h
@@ -42,6 +42,11 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
virtual void SetBeginFrameSource(
viz::BeginFrameSource* begin_frame_source) = 0;
virtual void DidReceiveCompositorFrameAck() = 0;
+ virtual void DidPresentCompositorFrame(uint32_t presentation_token,
+ base::TimeTicks time,
+ base::TimeDelta refresh,
+ uint32_t flags) = 0;
+ virtual void DidDiscardCompositorFrame(uint32_t presentation_token) = 0;
virtual void ReclaimResources(
const std::vector<viz::ReturnedResource>&) = 0;
virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
@@ -91,6 +96,8 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// Returns the local surface ID for this delegated content.
const viz::LocalSurfaceId& GetLocalSurfaceId() const;
+ void TakeFallbackContentFrom(DelegatedFrameHostAndroid* other);
+
private:
// viz::mojom::CompositorFrameSinkClient implementation.
void DidReceiveCompositorFrameAck(
diff --git a/chromium/ui/android/delegated_frame_host_android_unittest.cc b/chromium/ui/android/delegated_frame_host_android_unittest.cc
new file mode 100644
index 00000000000..fc0c6c4b95d
--- /dev/null
+++ b/chromium/ui/android/delegated_frame_host_android_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/android/delegated_frame_host_android.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/solid_color_layer.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/android/resources/resource_manager.h"
+#include "ui/android/view_android.h"
+#include "ui/android/window_android_compositor.h"
+
+namespace ui {
+namespace {
+
+using ::testing::Return;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Invoke;
+
+class MockDelegatedFrameHostAndroidClient
+ : public DelegatedFrameHostAndroid::Client {
+ public:
+ MOCK_METHOD1(SetBeginFrameSource, void(viz::BeginFrameSource*));
+ MOCK_METHOD0(DidReceiveCompositorFrameAck, void());
+ MOCK_METHOD4(DidPresentCompositorFrame,
+ void(uint32_t, base::TimeTicks, base::TimeDelta, uint32_t));
+ MOCK_METHOD1(DidDiscardCompositorFrame, void(uint32_t));
+ MOCK_METHOD1(ReclaimResources,
+ void(const std::vector<viz::ReturnedResource>&));
+ MOCK_METHOD1(OnFrameTokenChanged, void(uint32_t));
+};
+
+class MockWindowAndroidCompositor : public WindowAndroidCompositor {
+ public:
+ MOCK_METHOD0(GetWeakPtr, base::WeakPtr<ui::WindowAndroidCompositor>());
+ MOCK_METHOD0(IncrementReadbackRequestCount, void());
+ MOCK_METHOD0(DecrementReadbackRequestCount, void());
+ MOCK_METHOD1(DoRequestCopyOfOutputOnRootLayer, void(viz::CopyOutputRequest*));
+ MOCK_METHOD0(SetNeedsAnimate, void());
+ MOCK_METHOD0(GetResourceManager, ResourceManager&());
+ MOCK_METHOD0(GetFrameSinkId, viz::FrameSinkId());
+ MOCK_METHOD1(AddChildFrameSink, void(const viz::FrameSinkId&));
+ MOCK_METHOD1(RemoveChildFrameSink, void(const viz::FrameSinkId&));
+ MOCK_METHOD2(DoGetCompositorLock,
+ CompositorLock*(CompositorLockClient*, base::TimeDelta));
+ MOCK_CONST_METHOD0(IsDrawingFirstVisibleFrame, bool());
+
+ // Helpers for move-only types:
+ void RequestCopyOfOutputOnRootLayer(
+ std::unique_ptr<viz::CopyOutputRequest> request) override {
+ return DoRequestCopyOfOutputOnRootLayer(request.get());
+ }
+
+ std::unique_ptr<CompositorLock> GetCompositorLock(
+ CompositorLockClient* client,
+ base::TimeDelta time_delta) override {
+ return std::unique_ptr<CompositorLock>(
+ DoGetCompositorLock(client, time_delta));
+ }
+};
+
+class MockCompositorLockManagerClient : public ui::CompositorLockManagerClient {
+ public:
+ MOCK_METHOD1(OnCompositorLockStateChanged, void(bool));
+};
+
+class DelegatedFrameHostAndroidTest : public testing::Test {
+ public:
+ DelegatedFrameHostAndroidTest()
+ : frame_sink_id_(1, 1),
+ task_runner_(new base::TestMockTimeTaskRunner()),
+ lock_manager_(task_runner_, &lock_manager_client_) {
+ host_frame_sink_manager_.SetLocalManager(&frame_sink_manager_impl_);
+ view_.SetLayer(cc::SolidColorLayer::Create());
+ frame_host_ = std::make_unique<DelegatedFrameHostAndroid>(
+ &view_, &host_frame_sink_manager_, &client_, frame_sink_id_);
+ }
+
+ static viz::LocalSurfaceId GetFakeId() {
+ return viz::LocalSurfaceId(1, 1, base::UnguessableToken::Create());
+ }
+
+ ui::CompositorLock* GetLock(CompositorLockClient* client,
+ base::TimeDelta time_delta) {
+ return lock_manager_.GetCompositorLock(client, time_delta).release();
+ }
+
+ void SubmitCompositorFrame() {
+ viz::CompositorFrame frame;
+ auto render_pass = viz::RenderPass::Create();
+ render_pass->output_rect = gfx::Rect(10, 10);
+ frame.render_pass_list.push_back(std::move(render_pass));
+ frame.metadata.begin_frame_ack.sequence_number = 1;
+ frame.metadata.device_scale_factor = 1;
+ frame_host_->SubmitCompositorFrame(GetFakeId(), std::move(frame),
+ viz::mojom::HitTestRegionList::New());
+ }
+
+ protected:
+ MockWindowAndroidCompositor compositor_;
+ ui::ViewAndroid view_;
+ viz::FrameSinkManagerImpl frame_sink_manager_impl_;
+ viz::HostFrameSinkManager host_frame_sink_manager_;
+ MockDelegatedFrameHostAndroidClient client_;
+ viz::FrameSinkId frame_sink_id_;
+ std::unique_ptr<DelegatedFrameHostAndroid> frame_host_;
+ MockCompositorLockManagerClient lock_manager_client_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ CompositorLockManager lock_manager_;
+};
+
+TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringFirstFrame) {
+ // Attach during the first frame, lock will be taken.
+ EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).WillOnce(Return(true));
+ EXPECT_CALL(compositor_, DoGetCompositorLock(frame_host_.get(), _))
+ .WillOnce(Invoke(this, &DelegatedFrameHostAndroidTest::GetLock));
+ EXPECT_CALL(lock_manager_client_, OnCompositorLockStateChanged(true))
+ .Times(1);
+ frame_host_->AttachToCompositor(&compositor_);
+
+ // Lock should be released when we submit a compositor frame.
+ EXPECT_CALL(lock_manager_client_, OnCompositorLockStateChanged(false))
+ .Times(1);
+ SubmitCompositorFrame();
+}
+
+TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringLaterFrame) {
+ // Attach after the first frame, lock will not be taken.
+ EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame())
+ .WillOnce(Return(false));
+ EXPECT_CALL(compositor_, DoGetCompositorLock(_, _)).Times(0);
+ frame_host_->AttachToCompositor(&compositor_);
+}
+
+TEST_F(DelegatedFrameHostAndroidTest, CompositorLockWithDelegatedContent) {
+ // Submit a compositor frame to ensure we have delegated content.
+ SubmitCompositorFrame();
+
+ // Even though it's the first frame, we won't take the lock as we already have
+ // delegated content.
+ EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).WillOnce(Return(true));
+ EXPECT_CALL(compositor_, DoGetCompositorLock(_, _)).Times(0);
+ frame_host_->AttachToCompositor(&compositor_);
+}
+
+TEST_F(DelegatedFrameHostAndroidTest, CompositorLockReleasedWithDetach) {
+ // Attach during the first frame, lock will be taken.
+ EXPECT_CALL(compositor_, IsDrawingFirstVisibleFrame()).WillOnce(Return(true));
+ EXPECT_CALL(compositor_, DoGetCompositorLock(frame_host_.get(), _))
+ .WillOnce(Invoke(this, &DelegatedFrameHostAndroidTest::GetLock));
+ EXPECT_CALL(lock_manager_client_, OnCompositorLockStateChanged(true))
+ .Times(1);
+ frame_host_->AttachToCompositor(&compositor_);
+
+ // Lock should be released when we detach.
+ EXPECT_CALL(lock_manager_client_, OnCompositorLockStateChanged(false))
+ .Times(1);
+ frame_host_->DetachFromCompositor();
+}
+
+} // namespace
+} // namespace ui
diff --git a/chromium/ui/android/event_forwarder.cc b/chromium/ui/android/event_forwarder.cc
index 7be0652c95d..8386118ef39 100644
--- a/chromium/ui/android/event_forwarder.cc
+++ b/chromium/ui/android/event_forwarder.cc
@@ -128,8 +128,7 @@ void EventForwarder::OnMouseWheelEvent(JNIEnv* env,
jfloat x,
jfloat y,
jfloat ticks_x,
- jfloat ticks_y,
- jfloat pixels_per_tick) {
+ jfloat ticks_y) {
if (!ticks_x && !ticks_y)
return;
@@ -142,6 +141,11 @@ void EventForwarder::OnMouseWheelEvent(JNIEnv* env,
delta.InMicroseconds(), 1, 1000000, 50);
ui::MotionEventAndroid::Pointer pointer(
0, x, y, 0.0f /* touch_major */, 0.0f /* touch_minor */, 0.0f, 0.0f, 0);
+
+ auto* window = view_->GetWindowAndroid();
+ float pixels_per_tick =
+ window ? window->mouse_wheel_scroll_factor()
+ : kDefaultMouseWheelTickMultiplier * view_->GetDipScale();
ui::MotionEventAndroid event(
env, nullptr, 1.f / view_->GetDipScale(), ticks_x, ticks_y,
pixels_per_tick, time_ms, 0 /* action */, 1 /* pointer_count */,
@@ -188,13 +192,43 @@ bool EventForwarder::OnGestureEvent(JNIEnv* env,
scale, 0, 0, 0, 0, false, false));
}
-void EventForwarder::OnStartFling(JNIEnv* env,
- const JavaParamRef<jobject>& jobj,
- jlong time_ms,
- jfloat velocity_x,
- jfloat velocity_y,
- jboolean synthetic_scroll) {
- OnCancelFling(env, jobj, time_ms);
+void EventForwarder::Scroll(JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jfloat delta_x,
+ jfloat delta_y) {
+ float dip_scale = view_->GetDipScale();
+ float delta_xdip = delta_x / dip_scale;
+ float delta_ydip = delta_y / dip_scale;
+ view_->OnGestureEvent(GestureEventAndroid(
+ GESTURE_EVENT_TYPE_SCROLL_START, gfx::PointF(), gfx::PointF(), time_ms, 0,
+ -delta_xdip, -delta_ydip, 0, 0, true, false));
+ view_->OnGestureEvent(GestureEventAndroid(
+ GESTURE_EVENT_TYPE_SCROLL_BY, gfx::PointF(), gfx::PointF(), time_ms, 0,
+ -delta_xdip, -delta_ydip, 0, 0, true, false));
+ view_->OnGestureEvent(GestureEventAndroid(
+ GESTURE_EVENT_TYPE_SCROLL_END, gfx::PointF(), gfx::PointF(), time_ms, 0,
+ -delta_xdip, -delta_ydip, 0, 0, true, false));
+}
+
+void EventForwarder::DoubleTap(JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jint x,
+ jint y) {
+ float dip_scale = view_->GetDipScale();
+ view_->OnGestureEvent(GestureEventAndroid(
+ GESTURE_EVENT_TYPE_DOUBLE_TAP, gfx::PointF(x / dip_scale, y / dip_scale),
+ gfx::PointF(), time_ms, 0, 0, 0, 0, 0, true, false));
+}
+
+void EventForwarder::StartFling(JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jfloat velocity_x,
+ jfloat velocity_y,
+ jboolean synthetic_scroll) {
+ CancelFling(env, jobj, time_ms);
if (velocity_x == 0 && velocity_y == 0)
return;
// Use velocity as delta in scroll event.
@@ -206,9 +240,9 @@ void EventForwarder::OnStartFling(JNIEnv* env,
0, 0, velocity_x, velocity_y, true, synthetic_scroll));
}
-void EventForwarder::OnCancelFling(JNIEnv* env,
- const JavaParamRef<jobject>& jobj,
- jlong time_ms) {
+void EventForwarder::CancelFling(JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ jlong time_ms) {
view_->OnGestureEvent(
GestureEventAndroid(GESTURE_EVENT_TYPE_FLING_CANCEL, gfx::PointF(),
gfx::PointF(), time_ms, 0, 0, 0, 0, 0, false, false));
diff --git a/chromium/ui/android/event_forwarder.h b/chromium/ui/android/event_forwarder.h
index 68bd4db9735..efeac487b2f 100644
--- a/chromium/ui/android/event_forwarder.h
+++ b/chromium/ui/android/event_forwarder.h
@@ -71,8 +71,7 @@ class EventForwarder {
jfloat x,
jfloat y,
jfloat ticks_x,
- jfloat ticks_y,
- jfloat pixels_per_tick);
+ jfloat ticks_y);
void OnDragEvent(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj,
@@ -90,16 +89,28 @@ class EventForwarder {
jlong time_ms,
jfloat scale);
- void OnStartFling(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& jobj,
- jlong time_ms,
- jfloat velocity_x,
- jfloat velocity_y,
- jboolean synthetic_scroll);
-
- void OnCancelFling(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& jobj,
- jlong time_ms);
+ void Scroll(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jfloat delta_x,
+ jfloat delta_y);
+
+ void DoubleTap(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jint x,
+ jint y);
+
+ void StartFling(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ jlong time_ms,
+ jfloat velocity_x,
+ jfloat velocity_y,
+ jboolean synthetic_scroll);
+
+ void CancelFling(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ jlong time_ms);
private:
friend class ViewAndroid;
diff --git a/chromium/ui/android/resources/nine_patch_resource.cc b/chromium/ui/android/resources/nine_patch_resource.cc
index d665072defd..4e9a26b4d81 100644
--- a/chromium/ui/android/resources/nine_patch_resource.cc
+++ b/chromium/ui/android/resources/nine_patch_resource.cc
@@ -4,7 +4,6 @@
#include "ui/android/resources/nine_patch_resource.h"
-#include "base/memory/ptr_util.h"
#include "cc/layers/nine_patch_layer.h"
#include "ui/gfx/geometry/point_f.h"
diff --git a/chromium/ui/android/resources/resource.cc b/chromium/ui/android/resources/resource.cc
index 5ac17fa0556..385f253bb89 100644
--- a/chromium/ui/android/resources/resource.cc
+++ b/chromium/ui/android/resources/resource.cc
@@ -4,7 +4,6 @@
#include "ui/android/resources/resource.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/memory_usage_estimator.h"
namespace ui {
diff --git a/chromium/ui/android/resources/resource_manager_impl_unittest.cc b/chromium/ui/android/resources/resource_manager_impl_unittest.cc
index 58a16219901..ab9055b8f09 100644
--- a/chromium/ui/android/resources/resource_manager_impl_unittest.cc
+++ b/chromium/ui/android/resources/resource_manager_impl_unittest.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
diff --git a/chromium/ui/android/view_android.cc b/chromium/ui/android/view_android.cc
index b1b489e06f5..a2e12fc1909 100644
--- a/chromium/ui/android/view_android.cc
+++ b/chromium/ui/android/view_android.cc
@@ -13,7 +13,7 @@
#include "base/stl_util.h"
#include "cc/layers/layer.h"
#include "jni/ViewAndroidDelegate_jni.h"
-#include "third_party/WebKit/public/platform/WebCursorInfo.h"
+#include "third_party/blink/public/platform/web_cursor_info.h"
#include "ui/android/event_forwarder.h"
#include "ui/android/view_client.h"
#include "ui/android/window_android.h"
@@ -277,6 +277,23 @@ void ViewAndroid::RemoveObserver(ViewAndroidObserver* observer) {
observer_list_.RemoveObserver(observer);
}
+void ViewAndroid::RequestDisallowInterceptTouchEvent() {
+ ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
+ if (delegate.is_null())
+ return;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_ViewAndroidDelegate_requestDisallowInterceptTouchEvent(env, delegate);
+}
+
+void ViewAndroid::RequestUnbufferedDispatch(const MotionEventAndroid& event) {
+ ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
+ if (delegate.is_null())
+ return;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_ViewAndroidDelegate_requestUnbufferedDispatch(env, delegate,
+ event.GetJavaObject());
+}
+
void ViewAndroid::OnAttachedToWindow() {
for (auto& observer : observer_list_)
observer.OnAttachedToWindow();
diff --git a/chromium/ui/android/view_android.h b/chromium/ui/android/view_android.h
index 43faf43a1a7..5d32b20a4b1 100644
--- a/chromium/ui/android/view_android.h
+++ b/chromium/ui/android/view_android.h
@@ -167,6 +167,11 @@ class UI_ANDROID_EXPORT ViewAndroid {
void AddObserver(ViewAndroidObserver* observer);
void RemoveObserver(ViewAndroidObserver* observer);
+ void RequestDisallowInterceptTouchEvent();
+ void RequestUnbufferedDispatch(const MotionEventAndroid& event);
+
+ ViewAndroid* parent() const { return parent_; }
+
protected:
ViewAndroid* parent_;
diff --git a/chromium/ui/android/window_android.cc b/chromium/ui/android/window_android.cc
index 2520b391470..9b28a66e033 100644
--- a/chromium/ui/android/window_android.cc
+++ b/chromium/ui/android/window_android.cc
@@ -24,6 +24,8 @@ using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
+const float kDefaultMouseWheelTickMultiplier = 64;
+
class WindowAndroid::WindowBeginFrameSource : public viz::BeginFrameSource {
public:
explicit WindowBeginFrameSource(WindowAndroid* window)
@@ -125,12 +127,18 @@ WindowAndroid* WindowAndroid::FromJavaWindowAndroid(
AttachCurrentThread(), jwindow_android));
}
-WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj, int display_id)
+WindowAndroid::WindowAndroid(JNIEnv* env,
+ jobject obj,
+ int display_id,
+ float scroll_factor)
: display_id_(display_id),
compositor_(NULL),
begin_frame_source_(new WindowBeginFrameSource(this)),
needs_begin_frames_(false) {
java_window_.Reset(env, obj);
+ mouse_wheel_scroll_factor_ =
+ scroll_factor > 0 ? scroll_factor
+ : kDefaultMouseWheelTickMultiplier * GetDipScale();
}
void WindowAndroid::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -295,8 +303,10 @@ ScopedJavaLocalRef<jobject> WindowAndroid::GetWindowToken() {
jlong JNI_WindowAndroid_Init(JNIEnv* env,
const JavaParamRef<jobject>& obj,
- int sdk_display_id) {
- WindowAndroid* window = new WindowAndroid(env, obj, sdk_display_id);
+ int sdk_display_id,
+ float scroll_factor) {
+ WindowAndroid* window =
+ new WindowAndroid(env, obj, sdk_display_id, scroll_factor);
return reinterpret_cast<intptr_t>(window);
}
diff --git a/chromium/ui/android/window_android.h b/chromium/ui/android/window_android.h
index 35d3b7aa6be..91f8c079ac6 100644
--- a/chromium/ui/android/window_android.h
+++ b/chromium/ui/android/window_android.h
@@ -31,6 +31,8 @@ class BeginFrameSource;
namespace ui {
+extern const float kDefaultMouseWheelTickMultiplier;
+
class WindowAndroidCompositor;
class WindowAndroidObserver;
@@ -41,7 +43,7 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
static WindowAndroid* FromJavaWindowAndroid(
const base::android::JavaParamRef<jobject>& jwindow_android);
- WindowAndroid(JNIEnv* env, jobject obj, int display_id);
+ WindowAndroid(JNIEnv* env, jobject obj, int display_id, float scroll_factor);
~WindowAndroid() override;
@@ -86,6 +88,8 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
// Return whether the specified Android permission can be requested by Chrome.
bool CanRequestPermission(const std::string& permission);
+ float mouse_wheel_scroll_factor() const { return mouse_wheel_scroll_factor_; }
+
static WindowAndroid* CreateForTesting();
// Return the window token for this window, if one exists.
@@ -114,6 +118,7 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
std::unique_ptr<WindowBeginFrameSource> begin_frame_source_;
bool needs_begin_frames_;
std::list<base::Closure> vsync_complete_callbacks_;
+ float mouse_wheel_scroll_factor_;
DISALLOW_COPY_AND_ASSIGN(WindowAndroid);
};
diff --git a/chromium/ui/android/window_android_compositor.h b/chromium/ui/android/window_android_compositor.h
index 7446d2a4932..740e69e8486 100644
--- a/chromium/ui/android/window_android_compositor.h
+++ b/chromium/ui/android/window_android_compositor.h
@@ -7,15 +7,12 @@
#include <memory>
+#include "base/memory/weak_ptr.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/android/ui_android_export.h"
#include "ui/compositor/compositor_lock.h"
-namespace cc {
-class Layer;
-}
-
namespace ui {
class ResourceManager;
@@ -25,7 +22,9 @@ class UI_ANDROID_EXPORT WindowAndroidCompositor {
public:
virtual ~WindowAndroidCompositor() {}
- virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) = 0;
+ virtual base::WeakPtr<WindowAndroidCompositor> GetWeakPtr() = 0;
+ virtual void IncrementReadbackRequestCount() = 0;
+ virtual void DecrementReadbackRequestCount() = 0;
virtual void RequestCopyOfOutputOnRootLayer(
std::unique_ptr<viz::CopyOutputRequest> request) = 0;
virtual void SetNeedsAnimate() = 0;
diff --git a/chromium/ui/app_list/BUILD.gn b/chromium/ui/app_list/BUILD.gn
index 56706f28bd1..0189982a58f 100644
--- a/chromium/ui/app_list/BUILD.gn
+++ b/chromium/ui/app_list/BUILD.gn
@@ -9,6 +9,8 @@ assert(is_chromeos)
component("app_list") {
sources = [
+ "answer_card_contents_registry.cc",
+ "answer_card_contents_registry.h",
"app_list_constants.cc",
"app_list_constants.h",
"app_list_export.h",
@@ -21,23 +23,13 @@ component("app_list") {
"app_list_util.cc",
"app_list_util.h",
"app_list_view_delegate.h",
+ "assistant_interaction_model.h",
+ "assistant_interaction_model_observer.h",
"pagination_controller.cc",
"pagination_controller.h",
"pagination_model.cc",
"pagination_model.h",
"pagination_model_observer.h",
- "search/dictionary_data_store.cc",
- "search/dictionary_data_store.h",
- "search/history.cc",
- "search/history.h",
- "search/history_data.cc",
- "search/history_data.h",
- "search/history_data_observer.h",
- "search/history_data_store.cc",
- "search/history_data_store.h",
- "search/history_types.h",
- "search_provider.cc",
- "search_provider.h",
"views/app_list_drag_and_drop_host.h",
"views/app_list_folder_view.cc",
"views/app_list_folder_view.h",
@@ -54,6 +46,10 @@ component("app_list") {
"views/apps_grid_view.cc",
"views/apps_grid_view.h",
"views/apps_grid_view_folder_delegate.h",
+ "views/assistant_bubble_view.cc",
+ "views/assistant_bubble_view.h",
+ "views/assistant_container_view.cc",
+ "views/assistant_container_view.h",
"views/contents_view.cc",
"views/contents_view.h",
"views/expand_arrow_view.cc",
@@ -63,6 +59,10 @@ component("app_list") {
"views/folder_header_view.cc",
"views/folder_header_view.h",
"views/folder_header_view_delegate.h",
+ "views/horizontal_page.cc",
+ "views/horizontal_page.h",
+ "views/horizontal_page_container.cc",
+ "views/horizontal_page_container.h",
"views/image_shadow_animator.cc",
"views/image_shadow_animator.h",
"views/indicator_chip_view.cc",
@@ -92,6 +92,8 @@ component("app_list") {
"views/search_result_tile_item_view.h",
"views/search_result_view.cc",
"views/search_result_view.h",
+ "views/suggestion_chip_view.cc",
+ "views/suggestion_chip_view.h",
"views/suggestions_container_view.cc",
"views/suggestions_container_view.h",
"views/top_icon_animation_view.cc",
@@ -105,9 +107,9 @@ component("app_list") {
"//base:i18n",
"//base/third_party/dynamic_annotations",
"//cc/paint",
+ "//chromeos:chromeos",
"//components/keyed_service/core",
"//components/sync",
- "//components/wallpaper",
"//mojo/public/cpp/bindings",
"//services/ui/public/cpp",
"//services/ui/public/interfaces",
@@ -129,6 +131,7 @@ component("app_list") {
"//ui/resources",
"//ui/strings",
"//ui/views",
+ "//ui/views/mus/remote_view:remote_view_host",
"//ui/wm",
]
@@ -190,15 +193,8 @@ executable("app_list_demo") {
test("app_list_unittests") {
sources = [
- "app_list_item_list_unittest.cc",
- "app_list_model_unittest.cc",
"folder_image_unittest.cc",
"pagination_model_unittest.cc",
- "search/history_data_store_unittest.cc",
- "search/term_break_iterator_unittest.cc",
- "search/tokenized_string_char_iterator_unittest.cc",
- "search/tokenized_string_match_unittest.cc",
- "search/tokenized_string_unittest.cc",
"test/run_all_unittests.cc",
"views/app_list_main_view_unittest.cc",
"views/app_list_view_unittest.cc",
@@ -219,7 +215,7 @@ test("app_list_unittests") {
":test_support",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/accessibility",
diff --git a/chromium/ui/app_list/presenter/BUILD.gn b/chromium/ui/app_list/presenter/BUILD.gn
deleted file mode 100644
index 82d6dae01c9..00000000000
--- a/chromium/ui/app_list/presenter/BUILD.gn
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ui.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
-import("//testing/test.gni")
-
-assert(use_aura)
-
-mojom("mojom") {
- sources = [
- "app_list_presenter.mojom",
- ]
- deps = [
- "//services/ui/public/interfaces",
- ]
-
- component_output_prefix = "app_list_presenter_mojom"
- export_class_attribute = "APP_LIST_PRESENTER_EXPORT"
- export_define = "APP_LIST_PRESENTER_IMPLEMENTATION=1"
- export_header = "ui/app_list/presenter/app_list_presenter_export.h"
-}
-
-component("presenter") {
- sources = [
- "app_list.cc",
- "app_list.h",
- "app_list_delegate.h",
- "app_list_presenter_delegate.cc",
- "app_list_presenter_delegate.h",
- "app_list_presenter_delegate_factory.h",
- "app_list_presenter_export.h",
- "app_list_presenter_impl.cc",
- "app_list_presenter_impl.h",
- "app_list_view_delegate_factory.cc",
- "app_list_view_delegate_factory.h",
- ]
-
- defines = [ "APP_LIST_PRESENTER_IMPLEMENTATION" ]
-
- public_deps = [
- ":mojom",
- "//base",
- "//mojo/public/cpp/bindings",
- "//ui/app_list",
- "//ui/aura",
- "//ui/compositor",
- "//ui/gfx/geometry",
- "//ui/views",
-
- # Temporary dependency to fix compile flake in http://crbug.com/611898.
- # TODO(tapted): Remove once http://crbug.com/612382 is fixed.
- "//ui/accessibility:ax_enums_mojo",
- ]
-}
-
-static_library("test_support") {
- sources = [
- "test/app_list_presenter_impl_test_api.cc",
- "test/app_list_presenter_impl_test_api.h",
- "test/test_app_list_presenter.cc",
- "test/test_app_list_presenter.h",
- "test/test_app_list_view_delegate_factory.cc",
- "test/test_app_list_view_delegate_factory.h",
-
- # Temporary dependency to fix compile flake in http://crbug.com/611898.
- # TODO(tapted): Remove once http://crbug.com/612382 is fixed.
- "//ui/accessibility:ax_enums_mojo",
- ]
-
- public_deps = [
- ":mojom",
- ":presenter",
- ]
- deps = [
- "//base",
- "//mojo/public/cpp/bindings",
- "//ui/app_list:test_support",
- ]
-}
-
-test("app_list_presenter_unittests") {
- sources = [
- "app_list_presenter_impl_unittest.cc",
- "test/run_all_unittests.cc",
- ]
-
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- ":presenter",
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//testing/gtest",
- "//ui/app_list:test_support",
- "//ui/aura:aura",
- "//ui/aura:test_support",
- "//ui/base",
- "//ui/gl:test_support",
- "//ui/views:test_support",
- "//ui/wm:wm",
-
- # Temporary dependency to fix compile flake in http://crbug.com/611898.
- # TODO(tapted): Remove once http://crbug.com/612382 is fixed.
- "//ui/accessibility:ax_enums_mojo",
- ]
-
- data_deps = [
- "//ui/resources:ui_test_pak_data",
- ]
-}
diff --git a/chromium/ui/app_list/presenter/app_list_presenter.mojom b/chromium/ui/app_list/presenter/app_list_presenter.mojom
deleted file mode 100644
index 2b54979b6b2..00000000000
--- a/chromium/ui/app_list/presenter/app_list_presenter.mojom
+++ /dev/null
@@ -1,71 +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.
-
-module app_list.mojom;
-
-import "services/ui/public/interfaces/window_manager_constants.mojom";
-
-// TODO(msw): Rename this file to app_list.mojom; move to ash?
-// TODO(msw): Ash should implement the app list and presenter; chrome should
-// just push data about its apps into the app list interface.
-
-// Matches app_list::AppListView:AppListState.
-enum AppListState {
- // Closes |app_list_main_view_| and dismisses the delegate.
- CLOSED = 0,
- // The initial state for the app list when neither maximize or side shelf
- // modes are active. If set, the widget will peek over the shelf by
- // kPeekingAppListHeight DIPs.
- PEEKING = 1,
- // Entered when text is entered into the search box from peeking mode.
- HALF = 2,
- // Default app list state in maximize and side shelf modes. Entered from an
- // upward swipe from |PEEKING| or from clicking the chevron.
- FULLSCREEN_ALL_APPS = 3,
- // Entered from an upward swipe from |HALF| or by entering text in the
- // search box from |FULLSCREEN_ALL_APPS|.
- FULLSCREEN_SEARCH = 4,
-};
-
-// Implemented by ash. Used by chrome to set the presenter interface.
-interface AppList {
- // Set the app list presenter interface, to let ash trigger Chrome's app list.
- SetAppListPresenter(AppListPresenter presenter);
-
- // Notify the app list that the presenter's [target] visibility changed.
- OnTargetVisibilityChanged(bool visible);
-
- // |display_id| gives the display containing the app list.
- OnVisibilityChanged(bool visible, int64 display_id);
-};
-
-// Implemented by chrome. Used by ash to actually show and dismiss the app list.
-interface AppListPresenter {
- // Show the app list on the specified display.
- Show(int64 display_id);
-
- // Dismiss the app list.
- Dismiss();
-
- // Show the app list (on the specified display) if it is hidden; hide the
- // app list if it is shown.
- ToggleAppList(int64 display_id);
-
- // Starts a voice interaction session.
- StartVoiceInteractionSession();
-
- // Starts or stops a voice interaction session based on the current state.
- ToggleVoiceInteractionSession();
-
- // Updates y position and opacity of app list.
- UpdateYPositionAndOpacity(int32 y_position_in_screen,
- float background_opacity);
-
- // Ends the drag of app list from shelf.
- EndDragFromShelf(AppListState app_list_state);
-
- // Passes MouseWheelEvents from the Shelf to the AppListView.
- ProcessMouseWheelOffset(int32 y_scroll_offset);
-
-};
diff --git a/chromium/ui/app_list/vector_icons/BUILD.gn b/chromium/ui/app_list/vector_icons/BUILD.gn
index c9c66f798ea..f667bec6fa8 100644
--- a/chromium/ui/app_list/vector_icons/BUILD.gn
+++ b/chromium/ui/app_list/vector_icons/BUILD.gn
@@ -8,33 +8,18 @@ aggregate_vector_icons("app_list_vector_icons") {
icon_directory = "."
icons = [
- "ic_arrow_up.1x.icon",
"ic_arrow_up.icon",
- "ic_badge_instant.1x.icon",
"ic_badge_instant.icon",
- "ic_badge_play.1x.icon",
"ic_badge_play.icon",
- "ic_badge_rating.1x.icon",
"ic_badge_rating.icon",
- "ic_bookmark.1x.icon",
"ic_bookmark.icon",
- "ic_close.1x.icon",
- "ic_close.icon",
- "ic_domain.1x.icon",
"ic_domain.icon",
- "ic_equal.1x.icon",
"ic_equal.icon",
- "ic_google_black.1x.icon",
"ic_google_black.icon",
- "ic_google_color.1x.icon",
"ic_google_color.icon",
- "ic_history.1x.icon",
"ic_history.icon",
- "ic_mic_black.1x.icon",
"ic_mic_black.icon",
- "ic_search.1x.icon",
"ic_search.icon",
- "ic_search_engine_not_google.1x.icon",
"ic_search_engine_not_google.icon",
]
}
diff --git a/chromium/ui/arc/BUILD.gn b/chromium/ui/arc/BUILD.gn
index 40b7f36cf0b..ecc44786636 100644
--- a/chromium/ui/arc/BUILD.gn
+++ b/chromium/ui/arc/BUILD.gn
@@ -34,7 +34,7 @@ static_library("arc") {
"//components/exo",
"//components/keyed_service/content:content",
"//components/signin/core/account_id",
- "//mojo/common:common_base",
+ "//mojo/public/cpp/system",
"//skia",
"//ui/accessibility",
"//ui/aura",
@@ -52,6 +52,19 @@ static_library("arc") {
]
}
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "notification/mock_arc_notification_item.cc",
+ "notification/mock_arc_notification_item.h",
+ ]
+
+ deps = [
+ ":arc",
+ "//ui/gl:test_support",
+ ]
+}
+
test("ui_arc_unittests") {
testonly = true
sources = [
@@ -63,13 +76,14 @@ test("ui_arc_unittests") {
deps = [
":arc",
+ ":test_support",
"//ash:test_support_without_content",
"//base",
"//base/test:test_support",
"//components/arc:arc_test_support",
"//components/exo",
"//components/exo:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//testing/gmock",
"//testing/gtest",
"//ui/aura:test_support",
diff --git a/chromium/ui/arc/OWNERS b/chromium/ui/arc/OWNERS
index d7d81e7a131..853205b1bd1 100644
--- a/chromium/ui/arc/OWNERS
+++ b/chromium/ui/arc/OWNERS
@@ -1,3 +1,7 @@
+# This is for the common case of adding or renaming files. If you're doing
+# structural changes, use usual OWNERS rules.
+per-file BUILD.gn=*
+
elijahtaylor@chromium.org
hidehiko@chromium.org
lhchavez@chromium.org
diff --git a/chromium/ui/arc/notification/arc_notification_content_view.cc b/chromium/ui/arc/notification/arc_notification_content_view.cc
index baecc8484c1..9a3ad45d84e 100644
--- a/chromium/ui/arc/notification/arc_notification_content_view.cc
+++ b/chromium/ui/arc/notification/arc_notification_content_view.cc
@@ -6,7 +6,6 @@
#include "ash/wm/window_util.h"
#include "base/auto_reset.h"
-#include "base/memory/ptr_util.h"
#include "components/exo/notification_surface.h"
#include "components/exo/surface.h"
#include "ui/accessibility/ax_node_data.h"
@@ -18,8 +17,9 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/transform.h"
+#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/message_center/views/notification_control_buttons_view.h"
+#include "ui/message_center/public/cpp/notification.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/widget/root_view.h"
@@ -231,50 +231,19 @@ class ArcNotificationContentView::SlideHelper
DISALLOW_COPY_AND_ASSIGN(SlideHelper);
};
-class ArcNotificationContentView::ContentViewDelegate
- : public ArcNotificationContentViewDelegate {
- public:
- explicit ContentViewDelegate(ArcNotificationContentView* owner)
- : owner_(owner) {}
-
- void UpdateControlButtonsVisibility() override {
- owner_->UpdateControlButtonsVisibility();
- }
-
- void OnSlideChanged() override {
- if (owner_->slide_helper_)
- owner_->slide_helper_->Update();
- }
-
- message_center::NotificationControlButtonsView* GetControlButtonsView()
- const override {
- return owner_->control_buttons_view_;
- }
-
- void OnContainerAnimationStarted() override {
- owner_->OnContainerAnimationStarted();
- }
-
- void OnContainerAnimationEnded() override {
- owner_->OnContainerAnimationEnded();
- }
-
- private:
- ArcNotificationContentView* const owner_;
-
- DISALLOW_COPY_AND_ASSIGN(ContentViewDelegate);
-};
-
// static, for ArcNotificationContentView::GetClassName().
const char ArcNotificationContentView::kViewClassName[] =
"ArcNotificationContentView";
ArcNotificationContentView::ArcNotificationContentView(
- ArcNotificationItem* item)
+ ArcNotificationItem* item,
+ const message_center::Notification& notification,
+ message_center::MessageView* message_view)
: item_(item),
notification_key_(item->GetNotificationKey()),
event_forwarder_(new EventForwarder(this)),
- mouse_enter_exit_handler_(new MouseEnterExitHandler(this)) {
+ mouse_enter_exit_handler_(new MouseEnterExitHandler(this)),
+ control_buttons_view_(message_view) {
// kNotificationWidth must be 360, since this value is separately defiend in
// ArcNotificationWrapperView class in Android side.
DCHECK_EQ(360, message_center::kNotificationWidth);
@@ -294,10 +263,17 @@ ArcNotificationContentView::ArcNotificationContentView(
OnNotificationSurfaceAdded(surface);
}
+ // Creates the control_buttons_view_, which collects all control buttons into
+ // a horizontal box.
+ control_buttons_view_.set_owned_by_client();
+ control_buttons_view_.SetBackgroundColor(
+ GetControlButtonBackgroundColor(item_->GetShownContents()));
+
+ Update(message_view, notification);
+
// Create a layer as an anchor to insert surface copy during a slide.
SetPaintToLayer();
UpdatePreferredSize();
- UpdateAccessibleName();
}
ArcNotificationContentView::~ArcNotificationContentView() {
@@ -316,10 +292,66 @@ const char* ArcNotificationContentView::GetClassName() const {
return kViewClassName;
}
-std::unique_ptr<ArcNotificationContentViewDelegate>
-ArcNotificationContentView::CreateContentViewDelegate() {
- return std::make_unique<ArcNotificationContentView::ContentViewDelegate>(
- this);
+void ArcNotificationContentView::Update(
+ message_center::MessageView* message_view,
+ const message_center::Notification& notification) {
+ control_buttons_view_.ShowSettingsButton(
+ notification.should_show_settings_button());
+ control_buttons_view_.ShowCloseButton(!message_view->GetPinned());
+ control_buttons_view_.SetBackgroundColor(
+ GetControlButtonBackgroundColor(item_->GetShownContents()));
+ UpdateControlButtonsVisibility();
+
+ accessible_name_ = notification.accessible_name();
+ UpdateSnapshot();
+}
+
+message_center::NotificationControlButtonsView*
+ArcNotificationContentView::GetControlButtonsView() {
+ // |control_buttons_view_| is hosted in |floating_control_buttons_widget_| and
+ // should not be used when there is no |floating_control_buttons_widget_|.
+ return floating_control_buttons_widget_ ? &control_buttons_view_ : nullptr;
+}
+
+void ArcNotificationContentView::UpdateControlButtonsVisibility() {
+ if (!control_buttons_view_.parent())
+ return;
+
+ // If the visibility change is ongoing, skip this method to prevent an
+ // infinite loop.
+ if (updating_control_buttons_visibility_)
+ return;
+
+ DCHECK(floating_control_buttons_widget_);
+
+ const bool target_visiblity =
+ IsMouseHovered() || (control_buttons_view_.IsCloseButtonFocused()) ||
+ (control_buttons_view_.IsSettingsButtonFocused());
+
+ if (target_visiblity == floating_control_buttons_widget_->IsVisible())
+ return;
+
+ // Add the guard to prevent an infinite loop. Changing visibility may generate
+ // an event and it may call thie method again.
+ base::AutoReset<bool> reset(&updating_control_buttons_visibility_, true);
+
+ if (target_visiblity)
+ floating_control_buttons_widget_->Show();
+ else
+ floating_control_buttons_widget_->Hide();
+}
+
+void ArcNotificationContentView::OnSlideChanged() {
+ if (slide_helper_)
+ slide_helper_->Update();
+}
+
+void ArcNotificationContentView::OnContainerAnimationStarted() {
+ ShowCopiedSurface();
+}
+
+void ArcNotificationContentView::OnContainerAnimationEnded() {
+ HideCopiedSurface();
}
void ArcNotificationContentView::MaybeCreateFloatingControlButtons() {
@@ -330,22 +362,9 @@ void ArcNotificationContentView::MaybeCreateFloatingControlButtons() {
if (!surface_ || !GetWidget() || !item_)
return;
- DCHECK(!control_buttons_view_);
+ DCHECK(!control_buttons_view_.parent());
DCHECK(!floating_control_buttons_widget_);
- CHECK_EQ(ArcNotificationView::kViewClassName, parent()->GetClassName());
- auto* notification_view = static_cast<ArcNotificationView*>(parent());
-
- // Creates the control_buttons_view_, which collects all control buttons into
- // a horizontal box.
- control_buttons_view_ =
- new message_center::NotificationControlButtonsView(notification_view);
- control_buttons_view_->SetBackgroundColor(
- GetControlButtonBackgroundColor(item_->GetShownContents()));
- control_buttons_view_->ShowSettingsButton(
- item_->IsOpeningSettingsSupported());
- control_buttons_view_->ShowCloseButton(!notification_view->GetPinned());
-
views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
@@ -353,7 +372,7 @@ void ArcNotificationContentView::MaybeCreateFloatingControlButtons() {
floating_control_buttons_widget_.reset(new views::Widget);
floating_control_buttons_widget_->Init(params);
- floating_control_buttons_widget_->SetContentsView(control_buttons_view_);
+ floating_control_buttons_widget_->SetContentsView(&control_buttons_view_);
floating_control_buttons_widget_->GetNativeWindow()->AddPreTargetHandler(
mouse_enter_exit_handler_.get());
@@ -369,9 +388,6 @@ void ArcNotificationContentView::SetSurface(ArcNotificationSurface* surface) {
if (surface_ == surface)
return;
- // Put null to |control_buttos|view_| before deleting the widget, since it may
- // be referred while deletion.
- control_buttons_view_ = nullptr;
// Reset |floating_control_buttons_widget_| when |surface_| is changed.
floating_control_buttons_widget_.reset();
@@ -428,34 +444,6 @@ void ArcNotificationContentView::UpdatePreferredSize() {
SetPreferredSize(preferred_size);
}
-void ArcNotificationContentView::UpdateControlButtonsVisibility() {
- if (!control_buttons_view_)
- return;
-
- // If the visibility change is ongoing, skip this method to prevent an
- // infinite loop.
- if (updating_control_buttons_visibility_)
- return;
-
- DCHECK(floating_control_buttons_widget_);
-
- const bool target_visiblity =
- IsMouseHovered() || (control_buttons_view_->IsCloseButtonFocused()) ||
- (control_buttons_view_->IsSettingsButtonFocused());
-
- if (target_visiblity == floating_control_buttons_widget_->IsVisible())
- return;
-
- // Add the guard to prevent an infinite loop. Changing visibility may generate
- // an event and it may call thie method again.
- base::AutoReset<bool> reset(&updating_control_buttons_visibility_, true);
-
- if (target_visiblity)
- floating_control_buttons_widget_->Show();
- else
- floating_control_buttons_widget_->Hide();
-}
-
void ArcNotificationContentView::UpdateSnapshot() {
// Bail if we have a |surface_| because it controls the sizes and paints UI.
if (surface_)
@@ -489,22 +477,6 @@ void ArcNotificationContentView::AttachSurface() {
MaybeCreateFloatingControlButtons();
}
-void ArcNotificationContentView::UpdateAccessibleName() {
- // Don't update the accessible name when we are about to be destroyed.
- if (!item_)
- return;
-
- accessible_name_ = item_->GetAccessibleName();
-}
-
-void ArcNotificationContentView::OnContainerAnimationStarted() {
- ShowCopiedSurface();
-}
-
-void ArcNotificationContentView::OnContainerAnimationEnded() {
- HideCopiedSurface();
-}
-
void ArcNotificationContentView::ShowCopiedSurface() {
if (!surface_)
return;
@@ -576,19 +548,17 @@ void ArcNotificationContentView::Layout() {
// be positioned without the need to consider the transform.
surface_->GetContentWindow()->SetTransform(transform);
- if (control_buttons_view_) {
- DCHECK(floating_control_buttons_widget_);
+ if (floating_control_buttons_widget_) {
gfx::Rect control_buttons_bounds(contents_bounds);
- int buttons_width = control_buttons_view_->GetPreferredSize().width();
- int buttons_height = control_buttons_view_->GetPreferredSize().height();
+ const gfx::Size button_size = control_buttons_view_.GetPreferredSize();
control_buttons_bounds.set_x(control_buttons_bounds.right() -
- buttons_width -
+ button_size.width() -
message_center::kControlButtonPadding);
control_buttons_bounds.set_y(control_buttons_bounds.y() +
message_center::kControlButtonPadding);
- control_buttons_bounds.set_width(buttons_width);
- control_buttons_bounds.set_height(buttons_height);
+ control_buttons_bounds.set_width(button_size.width());
+ control_buttons_bounds.set_height(button_size.height());
floating_control_buttons_widget_->SetBounds(control_buttons_bounds);
}
@@ -625,10 +595,14 @@ void ArcNotificationContentView::OnMouseExited(const ui::MouseEvent&) {
}
void ArcNotificationContentView::OnFocus() {
- CHECK_EQ(ArcNotificationView::kViewClassName, parent()->GetClassName());
+ CHECK_EQ(message_center::MessageView::kViewClassName,
+ parent()->GetClassName());
+ auto* notification_view = static_cast<ArcNotificationView*>(parent());
+ CHECK_EQ(ArcNotificationView::kMessageViewSubClassName,
+ notification_view->GetMessageViewSubClassName());
NativeViewHost::OnFocus();
- static_cast<ArcNotificationView*>(parent())->OnContentFocused();
+ notification_view->OnContentFocused();
if (surface_ && surface_->GetAXTreeId() != -1)
Activate();
@@ -640,10 +614,14 @@ void ArcNotificationContentView::OnBlur() {
return;
}
- CHECK_EQ(ArcNotificationView::kViewClassName, parent()->GetClassName());
+ CHECK_EQ(message_center::MessageView::kViewClassName,
+ parent()->GetClassName());
+ auto* notification_view = static_cast<ArcNotificationView*>(parent());
+ CHECK_EQ(ArcNotificationView::kMessageViewSubClassName,
+ notification_view->GetMessageViewSubClassName());
NativeViewHost::OnBlur();
- static_cast<ArcNotificationView*>(parent())->OnContentBlured();
+ notification_view->OnContentBlured();
}
void ArcNotificationContentView::Activate() {
@@ -683,6 +661,19 @@ void ArcNotificationContentView::GetAccessibleNodeData(
node_data->SetName(accessible_name_);
}
+void ArcNotificationContentView::OnAccessibilityEvent(ax::mojom::Event event) {
+ if (event == ax::mojom::Event::kTextSelectionChanged) {
+ // Activate and request focus on notification content view. If text
+ // selection changed event is dispatched, it indicates that user is going to
+ // type something inside Android notification. Widget of message center is
+ // not activated by default. We need to activate the widget. If other view
+ // in message center has focus, it can consume key event. We need to request
+ // focus to move it to this content view.
+ Activate();
+ RequestFocus();
+ }
+}
+
void ArcNotificationContentView::OnWindowBoundsChanged(
aura::Window* window,
const gfx::Rect& old_bounds,
@@ -708,16 +699,6 @@ void ArcNotificationContentView::OnItemDestroying() {
SetSurface(nullptr);
}
-void ArcNotificationContentView::OnItemUpdated() {
- UpdateAccessibleName();
- UpdateSnapshot();
- if (control_buttons_view_) {
- DCHECK(floating_control_buttons_widget_);
- control_buttons_view_->SetBackgroundColor(
- GetControlButtonBackgroundColor(item_->GetShownContents()));
- }
-}
-
void ArcNotificationContentView::OnNotificationSurfaceAdded(
ArcNotificationSurface* surface) {
if (surface->GetNotificationKey() != notification_key_)
diff --git a/chromium/ui/arc/notification/arc_notification_content_view.h b/chromium/ui/arc/notification/arc_notification_content_view.h
index fe405a0c4dd..2d4fdf39aba 100644
--- a/chromium/ui/arc/notification/arc_notification_content_view.h
+++ b/chromium/ui/arc/notification/arc_notification_content_view.h
@@ -9,13 +9,14 @@
#include <string>
#include "base/macros.h"
-#include "ui/arc/notification/arc_notification_content_view_delegate.h"
#include "ui/arc/notification/arc_notification_item.h"
#include "ui/arc/notification/arc_notification_surface_manager.h"
#include "ui/aura/window_observer.h"
+#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/views/controls/native/native_view_host.h"
namespace message_center {
+class Notification;
class NotificationControlButtonsView;
}
@@ -42,19 +43,25 @@ class ArcNotificationContentView
public:
static const char kViewClassName[];
- explicit ArcNotificationContentView(ArcNotificationItem* item);
+ ArcNotificationContentView(ArcNotificationItem* item,
+ const message_center::Notification& notification,
+ message_center::MessageView* message_view);
~ArcNotificationContentView() override;
// views::View overrides:
const char* GetClassName() const override;
- std::unique_ptr<ArcNotificationContentViewDelegate>
- CreateContentViewDelegate();
+ void Update(message_center::MessageView* message_view,
+ const message_center::Notification& notification);
+ message_center::NotificationControlButtonsView* GetControlButtonsView();
+ void UpdateControlButtonsVisibility();
+ void OnSlideChanged();
+ void OnContainerAnimationStarted();
+ void OnContainerAnimationEnded();
private:
friend class ArcNotificationContentViewTest;
- class ContentViewDelegate;
class EventForwarder;
class MouseEnterExitHandler;
class SettingsButton;
@@ -65,17 +72,13 @@ class ArcNotificationContentView
void MaybeCreateFloatingControlButtons();
void SetSurface(ArcNotificationSurface* surface);
void UpdatePreferredSize();
- void UpdateControlButtonsVisibility();
void UpdateSnapshot();
void AttachSurface();
void Activate();
- void UpdateAccessibleName();
void SetExpanded(bool expanded);
bool IsExpanded() const;
void SetManuallyExpandedOrCollapsed(bool value);
bool IsManuallyExpandedOrCollapsed() const;
- void OnContainerAnimationStarted();
- void OnContainerAnimationEnded();
void ShowCopiedSurface();
void HideCopiedSurface();
@@ -91,6 +94,7 @@ class ArcNotificationContentView
void OnBlur() override;
views::FocusTraversable* GetFocusTraversable() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+ void OnAccessibilityEvent(ax::mojom::Event event) override;
// aura::WindowObserver
void OnWindowBoundsChanged(aura::Window* window,
@@ -101,7 +105,6 @@ class ArcNotificationContentView
// ArcNotificationItem::Observer
void OnItemDestroying() override;
- void OnItemUpdated() override;
// ArcNotificationSurfaceManager::Observer:
void OnNotificationSurfaceAdded(ArcNotificationSurface* surface) override;
@@ -138,8 +141,8 @@ class ArcNotificationContentView
// it.
std::unique_ptr<views::Widget> floating_control_buttons_widget_;
- message_center::NotificationControlButtonsView* control_buttons_view_ =
- nullptr;
+ // This view is owned by client (this).
+ message_center::NotificationControlButtonsView control_buttons_view_;
// Protects from call loops between Layout and OnWindowBoundsChanged.
bool in_layout_ = false;
diff --git a/chromium/ui/arc/notification/arc_notification_content_view_delegate.h b/chromium/ui/arc/notification/arc_notification_content_view_delegate.h
deleted file mode 100644
index 2d8e4d04ffc..00000000000
--- a/chromium/ui/arc/notification/arc_notification_content_view_delegate.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ARC_NOTIFICATION_ARC_NOTIFICATION_CONTENT_VIEW_DELEGATE_H_
-#define UI_ARC_NOTIFICATION_ARC_NOTIFICATION_CONTENT_VIEW_DELEGATE_H_
-
-namespace message_center {
-class NotificationControlButtonsView;
-}
-
-namespace arc {
-
-// Delegate for a view that is hosted by CustomNotificationView.
-// TODO(yoshiki): Remove this delegate and call code in the content view
-// directly without delegate.
-class ArcNotificationContentViewDelegate {
- public:
- virtual ~ArcNotificationContentViewDelegate() = default;
- virtual void UpdateControlButtonsVisibility() = 0;
- virtual void OnSlideChanged() = 0;
- virtual message_center::NotificationControlButtonsView*
- GetControlButtonsView() const = 0;
- virtual void OnContainerAnimationStarted() = 0;
- virtual void OnContainerAnimationEnded() = 0;
-};
-
-} // namespace arc
-
-#endif // UI_ARC_NOTIFICATION_ARC_NOTIFICATION_CONTENT_VIEW_DELEGATE_H_
diff --git a/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc b/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc
index d69a751faf4..2a2fb6f029c 100644
--- a/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc
+++ b/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc
@@ -8,10 +8,15 @@
#include <string>
#include <utility>
+#include "ash/message_center/message_center_view.h"
#include "ash/shell.h"
+#include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
+#include "ash/system/web_notification/web_notification_tray.h"
#include "ash/test/ash_test_base.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
#include "components/exo/buffer.h"
#include "components/exo/keyboard.h"
#include "components/exo/keyboard_delegate.h"
@@ -28,6 +33,7 @@
#include "ui/arc/notification/arc_notification_surface.h"
#include "ui/arc/notification/arc_notification_surface_manager_impl.h"
#include "ui/arc/notification/arc_notification_view.h"
+#include "ui/arc/notification/mock_arc_notification_item.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -45,7 +51,6 @@ namespace arc {
namespace {
-constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_";
constexpr gfx::Rect kNotificationSurfaceBounds(100, 100, 300, 300);
class MockKeyboardDelegate : public exo::KeyboardDelegate {
@@ -69,63 +74,6 @@ aura::Window* GetFocusedWindow() {
} // anonymous namespace
-class MockArcNotificationItem : public ArcNotificationItem {
- public:
- MockArcNotificationItem(const std::string& notification_key)
- : notification_key_(notification_key),
- notification_id_(kNotificationIdPrefix + notification_key),
- weak_factory_(this) {}
-
- // Methods for testing.
- size_t count_close() { return count_close_; }
- base::WeakPtr<MockArcNotificationItem> GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
- }
-
- // Overriding methods for testing.
- void Close(bool by_user) override { count_close_++; }
- const gfx::ImageSkia& GetSnapshot() const override { return snapshot_; }
- const std::string& GetNotificationKey() const override {
- return notification_key_;
- }
- const std::string& GetNotificationId() const override {
- return notification_id_;
- }
-
- // Overriding methods for returning dummy data or doing nothing.
- void OnClosedFromAndroid() override {}
- void Click() override {}
- void ToggleExpansion() override {}
- void OpenSettings() override {}
- void AddObserver(Observer* observer) override {}
- void RemoveObserver(Observer* observer) override {}
- void IncrementWindowRefCount() override {}
- void DecrementWindowRefCount() override {}
- bool IsOpeningSettingsSupported() const override { return true; }
- mojom::ArcNotificationExpandState GetExpandState() const override {
- return mojom::ArcNotificationExpandState::FIXED_SIZE;
- }
- mojom::ArcNotificationShownContents GetShownContents() const override {
- return mojom::ArcNotificationShownContents::CONTENTS_SHOWN;
- }
- gfx::Rect GetSwipeInputRect() const override { return gfx::Rect(); }
- const base::string16& GetAccessibleName() const override {
- return base::EmptyString16();
- };
- void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) override {}
- bool IsManuallyExpandedOrCollapsed() const override { return false; }
-
- private:
- std::string notification_key_;
- std::string notification_id_;
- gfx::ImageSkia snapshot_;
- size_t count_close_ = 0;
-
- base::WeakPtrFactory<MockArcNotificationItem> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MockArcNotificationItem);
-};
-
class DummyEvent : public ui::Event {
public:
DummyEvent() : Event(ui::ET_UNKNOWN, base::TimeTicks(), 0) {}
@@ -140,6 +88,8 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
void SetUp() override {
ash::AshTestBase::SetUp();
+ ash::MessageCenterView::disable_animation_for_testing = true;
+
wm_helper_ = std::make_unique<exo::WMHelper>();
exo::WMHelper::SetInstance(wm_helper_.get());
DCHECK(exo::WMHelper::HasInstance());
@@ -167,13 +117,14 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
ash::AshTestBase::TearDown();
}
- void PressCloseButton() {
+ void PressCloseButton(ArcNotificationView* notification_view) {
DummyEvent dummy_event;
auto* control_buttons_view =
- GetArcNotificationContentView()->control_buttons_view_;
+ &notification_view->content_view_->control_buttons_view_;
ASSERT_TRUE(control_buttons_view);
views::Button* close_button = control_buttons_view->close_button();
ASSERT_NE(nullptr, close_button);
+ close_button->RequestFocus();
control_buttons_view->ButtonPressed(close_button, dummy_event);
}
@@ -193,8 +144,8 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
static_cast<ArcNotificationView*>(
message_center::MessageViewFactory::Create(notification, true)));
notification_view->set_owned_by_client();
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.context = ash::Shell::GetPrimaryRootWindow();
auto wrapper_widget = std::make_unique<views::Widget>();
@@ -228,6 +179,9 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
}
Notification CreateNotification(MockArcNotificationItem* notification_item) {
+ message_center::RichNotificationData optional_fields;
+ optional_fields.settings_button_handler =
+ message_center::SettingsButtonHandler::DELEGATE;
return Notification(
message_center::NOTIFICATION_TYPE_CUSTOM,
notification_item->GetNotificationId(), base::UTF8ToUTF16("title"),
@@ -235,7 +189,7 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
GURL(),
message_center::NotifierId(message_center::NotifierId::ARC_APPLICATION,
"ARC_NOTIFICATION"),
- message_center::RichNotificationData(),
+ optional_fields,
new ArcNotificationDelegate(notification_item->GetWeakPtr()));
}
@@ -249,8 +203,7 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
message_center::NotificationControlButtonsView* GetControlButtonsView()
const {
DCHECK(GetArcNotificationContentView());
- DCHECK(GetArcNotificationContentView()->control_buttons_view_);
- return GetArcNotificationContentView()->control_buttons_view_;
+ return &GetArcNotificationContentView()->control_buttons_view_;
}
views::Widget* GetControlButtonsWidget() const {
DCHECK(GetControlButtonsView()->GetWidget());
@@ -258,9 +211,7 @@ class ArcNotificationContentViewTest : public ash::AshTestBase {
}
ArcNotificationContentView* GetArcNotificationContentView() const {
- views::View* view = notification_view_->contents_view_;
- EXPECT_EQ(ArcNotificationContentView::kViewClassName, view->GetClassName());
- return static_cast<ArcNotificationContentView*>(view);
+ return notification_view_->content_view_;
}
void ActivateArcNotification() {
GetArcNotificationContentView()->Activate();
@@ -339,13 +290,68 @@ TEST_F(ArcNotificationContentViewTest, CloseButton) {
EXPECT_TRUE(MessageCenter::Get()->FindVisibleNotificationById(
notification_item->GetNotificationId()));
- PressCloseButton();
+ PressCloseButton(notification_view());
EXPECT_FALSE(MessageCenter::Get()->FindVisibleNotificationById(
notification_item->GetNotificationId()));
CloseNotificationView();
}
+// Tests pressing close button when hosted in MessageCenterView.
+TEST_F(ArcNotificationContentViewTest, CloseButtonInMessageCenterView) {
+ std::string notification_key("notification id");
+
+ // Override MessageView factory to capture the created notification view in
+ // |notification_view|.
+ ArcNotificationView* notification_view = nullptr;
+ message_center::MessageViewFactory::SetCustomNotificationViewFactory(
+ base::BindLambdaForTesting(
+ [&notification_view](const message_center::Notification& notification)
+ -> std::unique_ptr<message_center::MessageView> {
+ auto* arc_delegate =
+ static_cast<ArcNotificationDelegate*>(notification.delegate());
+ std::unique_ptr<message_center::MessageView> created_view =
+ arc_delegate->CreateCustomMessageView(notification);
+ notification_view =
+ static_cast<ArcNotificationView*>(created_view.get());
+ return created_view;
+ }));
+
+ // Show MessageCenterView and activate its widget.
+ auto* notification_tray =
+ ash::StatusAreaWidgetTestHelper::GetStatusAreaWidget()
+ ->web_notification_tray();
+ notification_tray->ShowBubble(false /* show_by_click */);
+ notification_tray->GetBubbleView()
+ ->GetWidget()
+ ->widget_delegate()
+ ->set_can_activate(true);
+ notification_tray->GetBubbleView()->GetWidget()->Activate();
+
+ auto notification_item =
+ std::make_unique<MockArcNotificationItem>(notification_key);
+ PrepareSurface(notification_key);
+ Notification notification = CreateNotification(notification_item.get());
+
+ // Sets a close callback so that the underlying item is destroyed when close
+ // button is pressed. This simulates ArcNotificationItemImpl behavior.
+ notification_item->SetCloseCallback(base::BindLambdaForTesting(
+ [&notification_item]() { notification_item.reset(); }));
+
+ MessageCenter::Get()->AddNotification(
+ std::make_unique<Notification>(notification));
+ ASSERT_TRUE(notification_view);
+
+ // Cache notification id because |notification_item| will be gone when the
+ // close button is pressed.
+ const std::string notification_id = notification_item->GetNotificationId();
+ EXPECT_TRUE(
+ MessageCenter::Get()->FindVisibleNotificationById(notification_id));
+ PressCloseButton(notification_view);
+ EXPECT_FALSE(
+ MessageCenter::Get()->FindVisibleNotificationById(notification_id));
+}
+
TEST_F(ArcNotificationContentViewTest, ReuseSurfaceAfterClosing) {
std::string notification_key("notification id");
diff --git a/chromium/ui/arc/notification/arc_notification_delegate.cc b/chromium/ui/arc/notification/arc_notification_delegate.cc
index 4a3ddb0ac03..a689675b463 100644
--- a/chromium/ui/arc/notification/arc_notification_delegate.cc
+++ b/chromium/ui/arc/notification/arc_notification_delegate.cc
@@ -25,12 +25,7 @@ ArcNotificationDelegate::CreateCustomMessageView(
const message_center::Notification& notification) {
DCHECK(item_);
DCHECK_EQ(item_->GetNotificationId(), notification.id());
-
- auto view = std::make_unique<ArcNotificationContentView>(item_.get());
- auto content_view_delegate = view->CreateContentViewDelegate();
- return std::make_unique<ArcNotificationView>(item_.get(), std::move(view),
- std::move(content_view_delegate),
- notification);
+ return std::make_unique<ArcNotificationView>(item_.get(), notification);
}
void ArcNotificationDelegate::Close(bool by_user) {
@@ -38,7 +33,9 @@ void ArcNotificationDelegate::Close(bool by_user) {
item_->Close(by_user);
}
-void ArcNotificationDelegate::Click() {
+void ArcNotificationDelegate::Click(
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {
DCHECK(item_);
item_->Click();
}
diff --git a/chromium/ui/arc/notification/arc_notification_delegate.h b/chromium/ui/arc/notification/arc_notification_delegate.h
index c90da5dc3c5..34481382069 100644
--- a/chromium/ui/arc/notification/arc_notification_delegate.h
+++ b/chromium/ui/arc/notification/arc_notification_delegate.h
@@ -32,7 +32,8 @@ class ArcNotificationDelegate : public message_center::NotificationDelegate {
// message_center::NotificationDelegate overrides:
void Close(bool by_user) override;
- void Click() override;
+ void Click(const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override;
void SettingsClick() override;
private:
diff --git a/chromium/ui/arc/notification/arc_notification_item.h b/chromium/ui/arc/notification/arc_notification_item.h
index cbe94104602..e31015c3832 100644
--- a/chromium/ui/arc/notification/arc_notification_item.h
+++ b/chromium/ui/arc/notification/arc_notification_item.h
@@ -18,9 +18,6 @@ class ArcNotificationItem {
// Invoked when the notification data for this item has changed.
virtual void OnItemDestroying() = 0;
- // Invoked when the notification data for the item is updated.
- virtual void OnItemUpdated() = 0;
-
protected:
virtual ~Observer() = default;
};
@@ -32,7 +29,8 @@ class ArcNotificationItem {
virtual void OnClosedFromAndroid() = 0;
// Called when the notification is updated on Android-side. This is called
// from ArcNotificationManager.
- virtual void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) = 0;
+ virtual void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data,
+ const std::string& app_id) = 0;
// Called when the notification is closed on Chrome-side. This is called from
// ArcNotificationDelegate.
@@ -47,10 +45,6 @@ class ArcNotificationItem {
// Called when the user wants to toggle expansio of notification. This is
// called from ArcNotificationContentView.
virtual void ToggleExpansion() = 0;
- // Returns true if this notification has an intrinsic setting which shown
- // inside the notification content area. This is called from
- // ArcNotificationContentView.
- virtual bool IsOpeningSettingsSupported() const = 0;
// Adds an observer.
virtual void AddObserver(Observer* observer) = 0;
@@ -68,6 +62,8 @@ class ArcNotificationItem {
// Returns the current snapshot.
virtual const gfx::ImageSkia& GetSnapshot() const = 0;
// Returns the current expand state.
+ virtual mojom::ArcNotificationType GetNotificationType() const = 0;
+ // Returns the current expand state.
virtual mojom::ArcNotificationExpandState GetExpandState() const = 0;
virtual bool IsManuallyExpandedOrCollapsed() const = 0;
@@ -81,8 +77,6 @@ class ArcNotificationItem {
virtual const std::string& GetNotificationKey() const = 0;
// Returns the notification ID used in the Chrome message center.
virtual const std::string& GetNotificationId() const = 0;
- // Returnes the accessible name of the notification.
- virtual const base::string16& GetAccessibleName() const = 0;
};
} // namespace arc
diff --git a/chromium/ui/arc/notification/arc_notification_item_impl.cc b/chromium/ui/arc/notification/arc_notification_item_impl.cc
index a889206a543..40b317f87d3 100644
--- a/chromium/ui/arc/notification/arc_notification_item_impl.cc
+++ b/chromium/ui/arc/notification/arc_notification_item_impl.cc
@@ -7,7 +7,7 @@
#include <utility>
#include <vector>
-#include "base/memory/ptr_util.h"
+#include "ash/shelf/shelf_constants.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/arc/notification/arc_notification_delegate.h"
@@ -22,7 +22,6 @@ namespace arc {
namespace {
-constexpr char kNotifierId[] = "ARC_NOTIFICATION";
constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_";
// Converts from Android notification priority to Chrome notification priority.
@@ -68,7 +67,8 @@ ArcNotificationItemImpl::~ArcNotificationItemImpl() {
}
void ArcNotificationItemImpl::OnUpdatedFromAndroid(
- mojom::ArcNotificationDataPtr data) {
+ mojom::ArcNotificationDataPtr data,
+ const std::string& app_id) {
DCHECK(CalledOnValidThread());
DCHECK_EQ(notification_key_, data->key);
@@ -77,21 +77,17 @@ void ArcNotificationItemImpl::OnUpdatedFromAndroid(
rich_data.priority = ConvertAndroidPriority(data->priority);
if (data->small_icon)
rich_data.small_image = gfx::Image::CreateFrom1xBitmap(*data->small_icon);
- if (data->accessible_name.has_value()) {
- accessible_name_ = base::UTF8ToUTF16(*data->accessible_name);
- } else {
- accessible_name_ = base::JoinString(
- {base::UTF8ToUTF16(data->title), base::UTF8ToUTF16(data->message)},
- base::ASCIIToUTF16("\n"));
- }
- rich_data.accessible_name = accessible_name_;
- if (IsOpeningSettingsSupported()) {
+
+ rich_data.accessible_name = base::UTF8ToUTF16(
+ data->accessible_name.value_or(data->title + "\n" + data->message));
+ if (manager_->IsOpeningSettingsSupported()) {
rich_data.settings_button_handler =
message_center::SettingsButtonHandler::DELEGATE;
}
message_center::NotifierId notifier_id(
- message_center::NotifierId::ARC_APPLICATION, kNotifierId);
+ message_center::NotifierId::ARC_APPLICATION,
+ app_id.empty() ? ash::kDefaultArcNotifierId : app_id);
notifier_id.profile_id = profile_id_.GetUserEmail();
auto notification = std::make_unique<message_center::Notification>(
@@ -112,6 +108,7 @@ void ArcNotificationItemImpl::OnUpdatedFromAndroid(
manually_expanded_or_collapsed_ = true;
}
+ type_ = data->type;
expand_state_ = data->expand_state;
shown_contents_ = data->shown_contents;
swipe_input_rect_ =
@@ -128,9 +125,6 @@ void ArcNotificationItemImpl::OnUpdatedFromAndroid(
gfx::ImageSkiaRep(*data->snapshot_image, data->snapshot_image_scale));
}
- for (auto& observer : observers_)
- observer.OnItemUpdated();
-
message_center_->AddNotification(std::move(notification));
}
@@ -159,10 +153,6 @@ void ArcNotificationItemImpl::OpenSettings() {
manager_->OpenNotificationSettings(notification_key_);
}
-bool ArcNotificationItemImpl::IsOpeningSettingsSupported() const {
- return manager_->IsOpeningSettingsSupported();
-}
-
void ArcNotificationItemImpl::ToggleExpansion() {
switch (expand_state_) {
case mojom::ArcNotificationExpandState::EXPANDED:
@@ -208,6 +198,11 @@ const gfx::ImageSkia& ArcNotificationItemImpl::GetSnapshot() const {
return snapshot_;
}
+mojom::ArcNotificationType ArcNotificationItemImpl::GetNotificationType()
+ const {
+ return type_;
+}
+
mojom::ArcNotificationExpandState ArcNotificationItemImpl::GetExpandState()
const {
return expand_state_;
@@ -234,8 +229,4 @@ const std::string& ArcNotificationItemImpl::GetNotificationId() const {
return notification_id_;
}
-const base::string16& ArcNotificationItemImpl::GetAccessibleName() const {
- return accessible_name_;
-}
-
} // namespace arc
diff --git a/chromium/ui/arc/notification/arc_notification_item_impl.h b/chromium/ui/arc/notification/arc_notification_item_impl.h
index 33bea528b40..b1557fdcfc8 100644
--- a/chromium/ui/arc/notification/arc_notification_item_impl.h
+++ b/chromium/ui/arc/notification/arc_notification_item_impl.h
@@ -32,24 +32,24 @@ class ArcNotificationItemImpl : public ArcNotificationItem {
// ArcNotificationItem overrides:
void OnClosedFromAndroid() override;
- void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) override;
+ void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data,
+ const std::string& app_id) override;
void Close(bool by_user) override;
void Click() override;
void OpenSettings() override;
- bool IsOpeningSettingsSupported() const override;
void ToggleExpansion() override;
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void IncrementWindowRefCount() override;
void DecrementWindowRefCount() override;
const gfx::ImageSkia& GetSnapshot() const override;
+ mojom::ArcNotificationType GetNotificationType() const override;
mojom::ArcNotificationExpandState GetExpandState() const override;
bool IsManuallyExpandedOrCollapsed() const override;
mojom::ArcNotificationShownContents GetShownContents() const override;
gfx::Rect GetSwipeInputRect() const override;
const std::string& GetNotificationKey() const override;
const std::string& GetNotificationId() const override;
- const base::string16& GetAccessibleName() const override;
private:
// Return true if it's on the thread this instance is created on.
@@ -60,6 +60,8 @@ class ArcNotificationItemImpl : public ArcNotificationItem {
// The snapshot of the latest notification.
gfx::ImageSkia snapshot_;
+ // The type of the latest notification.
+ mojom::ArcNotificationType type_ = mojom::ArcNotificationType::SIMPLE;
// The expand state of the latest notification.
mojom::ArcNotificationExpandState expand_state_ =
mojom::ArcNotificationExpandState::FIXED_SIZE;
@@ -70,8 +72,6 @@ class ArcNotificationItemImpl : public ArcNotificationItem {
gfx::Rect swipe_input_rect_ = gfx::Rect();
// The reference counter of the window.
int window_ref_count_ = 0;
- // The accessible name of the latest notification.
- base::string16 accessible_name_;
base::ObserverList<Observer> observers_;
diff --git a/chromium/ui/arc/notification/arc_notification_manager.cc b/chromium/ui/arc/notification/arc_notification_manager.cc
index 98553c4b090..c015fc7162d 100644
--- a/chromium/ui/arc/notification/arc_notification_manager.cc
+++ b/chromium/ui/arc/notification/arc_notification_manager.cc
@@ -7,8 +7,6 @@
#include <memory>
#include <utility>
-#include "ash/shell.h"
-#include "ash/system/toast/toast_manager.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/stl_util.h"
@@ -130,7 +128,8 @@ void ArcNotificationManager::OnNotificationPosted(
const std::string& key = data->key;
auto it = items_.find(key);
if (it == items_.end()) {
- // Show a notification on the primary logged-in user's desktop.
+ // Show a notification on the primary logged-in user's desktop and badge the
+ // app icon in the shelf if the icon exists.
// TODO(yoshiki): Reconsider when ARC supports multi-user.
auto item = std::make_unique<ArcNotificationItemImpl>(
this, message_center_, key, main_profile_id_);
@@ -139,7 +138,9 @@ void ArcNotificationManager::OnNotificationPosted(
DCHECK(result.second);
it = result.first;
}
- it->second->OnUpdatedFromAndroid(std::move(data));
+ const std::string app_id =
+ data->package_name ? GetAppId(data->package_name.value()) : std::string();
+ it->second->OnUpdatedFromAndroid(std::move(data), app_id);
}
void ArcNotificationManager::OnNotificationUpdated(
@@ -154,7 +155,8 @@ void ArcNotificationManager::OnNotificationUpdated(
if (it == items_.end())
return;
- it->second->OnUpdatedFromAndroid(std::move(data));
+ const std::string app_id = GetAppId(data->package_name.value());
+ it->second->OnUpdatedFromAndroid(std::move(data), app_id);
}
void ArcNotificationManager::OnNotificationRemoved(const std::string& key) {
@@ -340,17 +342,8 @@ void ArcNotificationManager::SendNotificationToggleExpansionOnChrome(
key, mojom::ArcNotificationEvent::TOGGLE_EXPANSION);
}
-void ArcNotificationManager::OnToastPosted(mojom::ArcToastDataPtr data) {
- const base::string16 text16(
- base::UTF8ToUTF16(data->text.has_value() ? *data->text : std::string()));
- const base::string16 dismiss_text16(base::UTF8ToUTF16(
- data->dismiss_text.has_value() ? *data->dismiss_text : std::string()));
- ash::Shell::Get()->toast_manager()->Show(
- ash::ToastData(data->id, text16, data->duration, dismiss_text16));
-}
-
-void ArcNotificationManager::OnToastCancelled(mojom::ArcToastDataPtr data) {
- ash::Shell::Get()->toast_manager()->Cancel(data->id);
+void ArcNotificationManager::Shutdown() {
+ get_app_id_callback_.Reset();
}
bool ArcNotificationManager::ShouldIgnoreNotification(
@@ -361,4 +354,12 @@ bool ArcNotificationManager::ShouldIgnoreNotification(
*data->package_name == kPlayStorePackageName && IsRobotAccountMode();
}
+std::string ArcNotificationManager::GetAppId(
+ const std::string& package_name) const {
+ if (get_app_id_callback_.is_null())
+ return std::string();
+
+ return get_app_id_callback_.Run(package_name);
+}
+
} // namespace arc
diff --git a/chromium/ui/arc/notification/arc_notification_manager.h b/chromium/ui/arc/notification/arc_notification_manager.h
index 07058352b78..42279600213 100644
--- a/chromium/ui/arc/notification/arc_notification_manager.h
+++ b/chromium/ui/arc/notification/arc_notification_manager.h
@@ -51,6 +51,12 @@ class ArcNotificationManager
~ArcNotificationManager() override;
+ void set_get_app_id_callback(
+ base::RepeatingCallback<std::string(const std::string&)>
+ get_app_id_callback) {
+ get_app_id_callback_ = std::move(get_app_id_callback);
+ }
+
// ConnectionObserver<mojom::NotificationsInstance> implementation:
void OnConnectionReady() override;
void OnConnectionClosed() override;
@@ -59,8 +65,6 @@ class ArcNotificationManager
void OnNotificationPosted(mojom::ArcNotificationDataPtr data) override;
void OnNotificationUpdated(mojom::ArcNotificationDataPtr data) override;
void OnNotificationRemoved(const std::string& key) override;
- void OnToastPosted(mojom::ArcToastDataPtr data) override;
- void OnToastCancelled(mojom::ArcToastDataPtr data) override;
// Methods called from ArcNotificationItem:
void SendNotificationRemovedFromChrome(const std::string& key);
@@ -73,6 +77,9 @@ class ArcNotificationManager
bool IsOpeningSettingsSupported() const;
void SendNotificationToggleExpansionOnChrome(const std::string& key);
+ // Overridden from KeyedService:
+ void Shutdown() override;
+
private:
ArcNotificationManager(ArcBridgeService* bridge_service,
const AccountId& main_profile_id,
@@ -80,6 +87,9 @@ class ArcNotificationManager
bool ShouldIgnoreNotification(mojom::ArcNotificationData* data);
+ // Calls |get_app_id_callback_| to retrieve the app id from ArcAppListPrefs.
+ std::string GetAppId(const std::string& package_name) const;
+
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
const AccountId main_profile_id_;
message_center::MessageCenter* const message_center_;
@@ -88,6 +98,8 @@ class ArcNotificationManager
std::unordered_map<std::string, std::unique_ptr<ArcNotificationItem>>;
ItemMap items_;
+ base::RepeatingCallback<std::string(const std::string&)> get_app_id_callback_;
+
bool ready_ = false;
DISALLOW_COPY_AND_ASSIGN(ArcNotificationManager);
diff --git a/chromium/ui/arc/notification/arc_notification_manager_unittest.cc b/chromium/ui/arc/notification/arc_notification_manager_unittest.cc
index 98f586105d2..1ef695c1b7a 100644
--- a/chromium/ui/arc/notification/arc_notification_manager_unittest.cc
+++ b/chromium/ui/arc/notification/arc_notification_manager_unittest.cc
@@ -8,7 +8,6 @@
#include <utility>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "components/arc/arc_bridge_service.h"
@@ -85,6 +84,7 @@ class ArcNotificationManagerTest : public testing::Test {
data->key = key;
data->title = "TITLE";
data->message = "MESSAGE";
+ data->package_name = "PACKAGE_NAME";
arc_notification_manager()->OnNotificationPosted(std::move(data));
diff --git a/chromium/ui/arc/notification/arc_notification_surface_manager_impl.cc b/chromium/ui/arc/notification/arc_notification_surface_manager_impl.cc
index 29778a785b7..72c834d5bb3 100644
--- a/chromium/ui/arc/notification/arc_notification_surface_manager_impl.cc
+++ b/chromium/ui/arc/notification/arc_notification_surface_manager_impl.cc
@@ -7,7 +7,6 @@
#include <string>
#include <utility>
-#include "base/memory/ptr_util.h"
#include "components/exo/notification_surface.h"
#include "ui/arc/notification/arc_notification_surface_impl.h"
diff --git a/chromium/ui/arc/notification/arc_notification_view.cc b/chromium/ui/arc/notification/arc_notification_view.cc
index 6977d6d385f..1cee5514afb 100644
--- a/chromium/ui/arc/notification/arc_notification_view.cc
+++ b/chromium/ui/arc/notification/arc_notification_view.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "ui/accessibility/ax_action_data.h"
-#include "ui/arc/notification/arc_notification_content_view_delegate.h"
+#include "ui/arc/notification/arc_notification_content_view.h"
#include "ui/arc/notification/arc_notification_item.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
@@ -23,33 +23,26 @@
namespace arc {
// static
-const char ArcNotificationView::kViewClassName[] = "ArcNotificationView";
+const char ArcNotificationView::kMessageViewSubClassName[] =
+ "ArcNotificationView";
ArcNotificationView::ArcNotificationView(
ArcNotificationItem* item,
- std::unique_ptr<views::View> contents_view,
- std::unique_ptr<ArcNotificationContentViewDelegate> contents_view_delegate,
const message_center::Notification& notification)
: message_center::MessageView(notification),
item_(item),
- contents_view_(contents_view.get()),
- contents_view_delegate_(std::move(contents_view_delegate)) {
+ content_view_(new ArcNotificationContentView(item_, notification, this)) {
DCHECK_EQ(message_center::NOTIFICATION_TYPE_CUSTOM, notification.type());
item_->AddObserver(this);
- DCHECK(contents_view);
- AddChildView(contents_view.release());
+ AddChildView(content_view_);
- DCHECK(contents_view_delegate_);
-
- if (contents_view_->background()) {
+ if (content_view_->background()) {
background_view()->background()->SetNativeControlColor(
- contents_view_->background()->get_color());
+ content_view_->background()->get_color());
}
- UpdateControlButtonsVisibilityWithNotification(notification);
-
focus_painter_ = views::Painter::CreateSolidFocusPainter(
message_center::kFocusBorderColor, gfx::Insets(0, 1, 3, 2));
}
@@ -70,39 +63,23 @@ void ArcNotificationView::OnContentBlured() {
void ArcNotificationView::UpdateWithNotification(
const message_center::Notification& notification) {
message_center::MessageView::UpdateWithNotification(notification);
-
- UpdateControlButtonsVisibilityWithNotification(notification);
+ content_view_->Update(this, notification);
}
void ArcNotificationView::SetDrawBackgroundAsActive(bool active) {
- // Do nothing if |contents_view_| has a background.
- if (contents_view_->background())
+ // Do nothing if |content_view_| has a background.
+ if (content_view_->background())
return;
message_center::MessageView::SetDrawBackgroundAsActive(active);
}
-bool ArcNotificationView::IsCloseButtonFocused() const {
- if (!GetControlButtonsView())
- return false;
- return GetControlButtonsView()->IsCloseButtonFocused();
-}
-
-void ArcNotificationView::RequestFocusOnCloseButton() {
- if (GetControlButtonsView()) {
- GetControlButtonsView()->RequestFocusOnCloseButton();
- if (contents_view_delegate_)
- contents_view_delegate_->UpdateControlButtonsVisibility();
- }
-}
-
-const char* ArcNotificationView::GetClassName() const {
- return kViewClassName;
+void ArcNotificationView::UpdateControlButtonsVisibility() {
+ content_view_->UpdateControlButtonsVisibility();
}
-void ArcNotificationView::UpdateControlButtonsVisibility() {
- if (contents_view_delegate_)
- contents_view_delegate_->UpdateControlButtonsVisibility();
+const char* ArcNotificationView::GetMessageViewSubClassName() const {
+ return kMessageViewSubClassName;
}
void ArcNotificationView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
@@ -112,7 +89,7 @@ void ArcNotificationView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
message_center::NotificationControlButtonsView*
ArcNotificationView::GetControlButtonsView() const {
- return contents_view_delegate_->GetControlButtonsView();
+ return content_view_->GetControlButtonsView();
}
bool ArcNotificationView::IsExpanded() const {
@@ -120,6 +97,16 @@ bool ArcNotificationView::IsExpanded() const {
item_->GetExpandState() == mojom::ArcNotificationExpandState::EXPANDED;
}
+bool ArcNotificationView::IsAutoExpandingAllowed() const {
+ if (!item_)
+ return false;
+
+ // Disallow auto-expanding if the notificaiton is bundled. This is consistent
+ // behavior with Android since expanded height of bundle notification might be
+ // too long vertically.
+ return item_->GetNotificationType() != mojom::ArcNotificationType::BUNDLED;
+}
+
void ArcNotificationView::SetExpanded(bool expanded) {
if (!item_)
return;
@@ -141,75 +128,68 @@ bool ArcNotificationView::IsManuallyExpandedOrCollapsed() const {
}
void ArcNotificationView::OnContainerAnimationStarted() {
- if (contents_view_delegate_)
- contents_view_delegate_->OnContainerAnimationStarted();
+ content_view_->OnContainerAnimationStarted();
}
void ArcNotificationView::OnContainerAnimationEnded() {
- if (contents_view_delegate_)
- contents_view_delegate_->OnContainerAnimationEnded();
+ content_view_->OnContainerAnimationEnded();
}
void ArcNotificationView::OnSlideChanged() {
- if (contents_view_delegate_)
- contents_view_delegate_->OnSlideChanged();
+ content_view_->OnSlideChanged();
}
gfx::Size ArcNotificationView::CalculatePreferredSize() const {
const gfx::Insets insets = GetInsets();
const int contents_width = message_center::kNotificationWidth;
- const int contents_height = contents_view_->GetHeightForWidth(contents_width);
+ const int contents_height = content_view_->GetHeightForWidth(contents_width);
return gfx::Size(contents_width + insets.width(),
contents_height + insets.height());
}
void ArcNotificationView::Layout() {
// Setting the bounds before calling the parent to prevent double Layout.
- contents_view_->SetBoundsRect(GetContentsBounds());
+ content_view_->SetBoundsRect(GetContentsBounds());
message_center::MessageView::Layout();
// If the content view claims focus, defer focus handling to the content view.
- if (contents_view_->IsFocusable())
+ if (content_view_->IsFocusable())
SetFocusBehavior(FocusBehavior::NEVER);
}
bool ArcNotificationView::HasFocus() const {
// In case that focus handling is defered to the content view, asking the
// content view about focus.
- if (contents_view_ && contents_view_->IsFocusable())
- return contents_view_->HasFocus();
- else
- return message_center::MessageView::HasFocus();
+ return content_view_->IsFocusable() ? content_view_->HasFocus()
+ : message_center::MessageView::HasFocus();
}
void ArcNotificationView::RequestFocus() {
- if (contents_view_ && contents_view_->IsFocusable())
- contents_view_->RequestFocus();
+ if (content_view_->IsFocusable())
+ content_view_->RequestFocus();
else
message_center::MessageView::RequestFocus();
}
void ArcNotificationView::OnPaint(gfx::Canvas* canvas) {
MessageView::OnPaint(canvas);
- if (contents_view_ && contents_view_->IsFocusable())
- views::Painter::PaintFocusPainter(contents_view_, canvas,
+ if (content_view_->IsFocusable()) {
+ views::Painter::PaintFocusPainter(content_view_, canvas,
focus_painter_.get());
+ }
}
bool ArcNotificationView::OnKeyPressed(const ui::KeyEvent& event) {
- if (contents_view_) {
- ui::InputMethod* input_method = contents_view_->GetInputMethod();
- if (input_method) {
- ui::TextInputClient* text_input_client =
- input_method->GetTextInputClient();
- if (text_input_client &&
- text_input_client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
- // If the focus is in an edit box, we skip the special key handling for
- // back space and return keys. So that these key events are sent to the
- // arc container correctly without being handled by the message center.
- return false;
- }
+ ui::InputMethod* input_method = content_view_->GetInputMethod();
+ if (input_method) {
+ ui::TextInputClient* text_input_client = input_method->GetTextInputClient();
+ if (text_input_client &&
+ text_input_client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
+ // If the focus is in an edit box, we skip the special key handling for
+ // back space and return keys. So that these key events are sent to the
+ // arc container correctly without being handled by the message center.
+ return false;
}
}
@@ -235,19 +215,4 @@ void ArcNotificationView::OnItemDestroying() {
item_ = nullptr;
}
-void ArcNotificationView::OnItemUpdated() {}
-
-// TODO(yoshiki): move this to MessageView and share the code among
-// NotificationView and NotificationViewMD.
-void ArcNotificationView::UpdateControlButtonsVisibilityWithNotification(
- const message_center::Notification& notification) {
- if (!GetControlButtonsView())
- return;
-
- GetControlButtonsView()->ShowSettingsButton(
- notification.should_show_settings_button());
- GetControlButtonsView()->ShowCloseButton(!GetPinned());
- UpdateControlButtonsVisibility();
-}
-
} // namespace message_center
diff --git a/chromium/ui/arc/notification/arc_notification_view.h b/chromium/ui/arc/notification/arc_notification_view.h
index e54838bb0b5..2e9e64a4dc6 100644
--- a/chromium/ui/arc/notification/arc_notification_view.h
+++ b/chromium/ui/arc/notification/arc_notification_view.h
@@ -15,20 +15,17 @@ class Painter;
namespace arc {
-class ArcNotificationContentViewDelegate;
+class ArcNotificationContentView;
// View for custom notification with NOTIFICATION_TYPE_CUSTOM which hosts the
// ArcNotificationContentView which shows content of the notification.
class ArcNotificationView : public message_center::MessageView,
public ArcNotificationItem::Observer {
public:
- static const char kViewClassName[];
+ static const char kMessageViewSubClassName[];
// |content_view| is a view to be hosted in this view.
ArcNotificationView(ArcNotificationItem* item,
- std::unique_ptr<views::View> content_view,
- std::unique_ptr<ArcNotificationContentViewDelegate>
- contents_view_delegate,
const message_center::Notification& notification);
~ArcNotificationView() override;
@@ -41,23 +38,22 @@ class ArcNotificationView : public message_center::MessageView,
void UpdateWithNotification(
const message_center::Notification& notification) override;
void SetDrawBackgroundAsActive(bool active) override;
- bool IsCloseButtonFocused() const override;
- void RequestFocusOnCloseButton() override;
void UpdateControlButtonsVisibility() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
message_center::NotificationControlButtonsView* GetControlButtonsView()
const override;
bool IsExpanded() const override;
void SetExpanded(bool expanded) override;
+ bool IsAutoExpandingAllowed() const override;
bool IsManuallyExpandedOrCollapsed() const override;
void OnContainerAnimationStarted() override;
void OnContainerAnimationEnded() override;
+ const char* GetMessageViewSubClassName() const final;
// views::SlideOutController::Delegate:
void OnSlideChanged() override;
// Overridden from views::View:
- const char* GetClassName() const override;
gfx::Size CalculatePreferredSize() const override;
void Layout() override;
bool HasFocus() const override;
@@ -69,11 +65,11 @@ class ArcNotificationView : public message_center::MessageView,
// ArcNotificationItem::Observer
void OnItemDestroying() override;
- void OnItemUpdated() override;
private:
friend class ArcNotificationContentViewTest;
friend class ArcNotificationViewTest;
+ friend class ArcAccessibilityHelperBridgeTest;
// TODO(yoshiki): Mmove this to message_center::MessageView.
void UpdateControlButtonsVisibilityWithNotification(
@@ -82,8 +78,7 @@ class ArcNotificationView : public message_center::MessageView,
ArcNotificationItem* item_;
// The view for the custom content. Owned by view hierarchy.
- views::View* contents_view_ = nullptr;
- std::unique_ptr<ArcNotificationContentViewDelegate> contents_view_delegate_;
+ ArcNotificationContentView* const content_view_;
std::unique_ptr<views::Painter> focus_painter_;
diff --git a/chromium/ui/arc/notification/arc_notification_view_unittest.cc b/chromium/ui/arc/notification/arc_notification_view_unittest.cc
index e988fdd763b..bac3ab667ca 100644
--- a/chromium/ui/arc/notification/arc_notification_view_unittest.cc
+++ b/chromium/ui/arc/notification/arc_notification_view_unittest.cc
@@ -4,12 +4,13 @@
#include <memory>
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/arc/notification/arc_notification_content_view_delegate.h"
+#include "ui/arc/notification/arc_notification_content_view.h"
#include "ui/arc/notification/arc_notification_item.h"
#include "ui/arc/notification/arc_notification_view.h"
#include "ui/base/ime/dummy_text_input_client.h"
@@ -22,6 +23,7 @@
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/views/message_view_factory.h"
+#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/test/views_test_base.h"
@@ -34,59 +36,6 @@ namespace arc {
namespace {
constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_";
-const SkColor kBackgroundColor = SK_ColorGREEN;
-
-class TestNotificationContentsView : public views::View {
- public:
- TestNotificationContentsView() {
- SetFocusBehavior(FocusBehavior::ALWAYS);
- SetBackground(views::CreateSolidBackground(kBackgroundColor));
- SetPreferredSize(gfx::Size(100, 100));
- }
- ~TestNotificationContentsView() override = default;
-
- void Reset() {
- mouse_event_count_ = 0;
- keyboard_event_count_ = 0;
- }
-
- // views::View
- bool OnMousePressed(const ui::MouseEvent& event) override {
- ++mouse_event_count_;
- return true;
- }
- void OnMouseMoved(const ui::MouseEvent& event) override {
- ++mouse_event_count_;
- }
- void OnMouseReleased(const ui::MouseEvent& event) override {
- ++mouse_event_count_;
- }
- bool OnKeyPressed(const ui::KeyEvent& event) override {
- ++keyboard_event_count_;
- return false;
- }
-
- int mouse_event_count() const { return mouse_event_count_; }
- int keyboard_event_count() const { return keyboard_event_count_; }
-
- private:
- int mouse_event_count_ = 0;
- int keyboard_event_count_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(TestNotificationContentsView);
-};
-
-class TestContentViewDelegate : public ArcNotificationContentViewDelegate {
- public:
- void UpdateControlButtonsVisibility() override {}
- void OnSlideChanged() override {}
- message_center::NotificationControlButtonsView* GetControlButtonsView()
- const override {
- return nullptr;
- }
- void OnContainerAnimationStarted() override {}
- void OnContainerAnimationEnded() override {}
-};
class MockArcNotificationItem : public ArcNotificationItem {
public:
@@ -113,7 +62,9 @@ class MockArcNotificationItem : public ArcNotificationItem {
void RemoveObserver(Observer* observer) override {}
void IncrementWindowRefCount() override {}
void DecrementWindowRefCount() override {}
- bool IsOpeningSettingsSupported() const override { return true; }
+ mojom::ArcNotificationType GetNotificationType() const override {
+ return mojom::ArcNotificationType::SIMPLE;
+ }
mojom::ArcNotificationExpandState GetExpandState() const override {
return mojom::ArcNotificationExpandState::FIXED_SIZE;
}
@@ -121,10 +72,8 @@ class MockArcNotificationItem : public ArcNotificationItem {
return mojom::ArcNotificationShownContents::CONTENTS_SHOWN;
}
gfx::Rect GetSwipeInputRect() const override { return gfx::Rect(); }
- const base::string16& GetAccessibleName() const override {
- return base::EmptyString16();
- };
- void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) override {}
+ void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data,
+ const std::string& app_id) override {}
bool IsManuallyExpandedOrCollapsed() const override { return false; }
private:
@@ -135,14 +84,6 @@ class MockArcNotificationItem : public ArcNotificationItem {
DISALLOW_COPY_AND_ASSIGN(MockArcNotificationItem);
};
-std::unique_ptr<message_center::MessageView> CreateCustomMessageViewForTest(
- ArcNotificationItem* item,
- const Notification& notification) {
- return std::make_unique<ArcNotificationView>(
- item, std::make_unique<TestNotificationContentsView>(),
- std::make_unique<TestContentViewDelegate>(), notification);
-}
-
class TestTextInputClient : public ui::DummyTextInputClient {
public:
TestTextInputClient() : ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT) {}
@@ -159,21 +100,21 @@ class TestTextInputClient : public ui::DummyTextInputClient {
} // namespace
-class ArcNotificationViewTest : public views::ViewsTestBase {
+class ArcNotificationViewTest : public ash::AshTestBase {
public:
ArcNotificationViewTest() = default;
~ArcNotificationViewTest() override = default;
// views::ViewsTestBase
void SetUp() override {
- views::ViewsTestBase::SetUp();
-
- MessageCenter::Initialize();
+ ash::AshTestBase::SetUp();
const std::string notification_id("notification id");
item_ = std::make_unique<MockArcNotificationItem>(notification_id);
message_center::MessageViewFactory::SetCustomNotificationViewFactory(
- base::BindRepeating(&CreateCustomMessageViewForTest, item_.get()));
+ base::BindRepeating(
+ &ArcNotificationViewTest::CreateCustomMessageViewForTest,
+ base::Unretained(this), item_.get()));
notification_ = std::make_unique<Notification>(
message_center::NOTIFICATION_TYPE_CUSTOM, notification_id,
@@ -189,23 +130,24 @@ class ArcNotificationViewTest : public views::ViewsTestBase {
UpdateNotificationViews();
views::Widget::InitParams init_params(
- CreateParams(views::Widget::InitParams::TYPE_POPUP));
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.context = CurrentContext();
+ init_params.parent = ash::Shell::GetPrimaryRootWindow()->GetChildById(
+ ash::kShellWindowId_DefaultContainer);
+ init_params.ownership =
+ views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
views::Widget* widget = new views::Widget();
widget->Init(init_params);
widget->SetContentsView(notification_view_.get());
widget->SetSize(notification_view_->GetPreferredSize());
widget->Show();
+ EXPECT_EQ(widget, notification_view_->GetWidget());
}
void TearDown() override {
widget()->Close();
notification_view_.reset();
- views::ViewsTestBase::TearDown();
- MessageCenter::Shutdown();
- }
-
- SkColor GetBackgroundColor() const {
- return notification_view_->background_view()->background()->get_color();
+ ash::AshTestBase::TearDown();
}
void PerformClick(const gfx::Point& point) {
@@ -226,11 +168,6 @@ class ArcNotificationViewTest : public views::ViewsTestBase {
widget()->OnKeyEvent(&event2);
}
- void KeyPress(ui::KeyboardCode key_code) {
- ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
- widget()->OnKeyEvent(&event);
- }
-
void UpdateNotificationViews() {
MessageCenter::Get()->AddNotification(
std::make_unique<Notification>(*notification()));
@@ -249,10 +186,8 @@ class ArcNotificationViewTest : public views::ViewsTestBase {
}
void DispatchGesture(const ui::GestureEventDetails& details) {
- ui::test::EventGenerator generator(
- notification_view()->GetWidget()->GetNativeWindow());
- ui::GestureEvent event(0, 0, 0, ui::EventTimeForNow(), details);
- generator.Dispatch(&event);
+ ui::GestureEvent event2(0, 0, 0, ui::EventTimeForNow(), details);
+ widget()->OnGestureEvent(&event2);
}
void BeginScroll() {
@@ -269,14 +204,22 @@ class ArcNotificationViewTest : public views::ViewsTestBase {
}
Notification* notification() { return notification_.get(); }
- TestNotificationContentsView* contents_view() {
- return static_cast<TestNotificationContentsView*>(
- notification_view_->contents_view_);
+ ArcNotificationContentView* content_view() {
+ return notification_view_->content_view_;
}
views::Widget* widget() { return notification_view_->GetWidget(); }
ArcNotificationView* notification_view() { return notification_view_.get(); }
private:
+ std::unique_ptr<message_center::MessageView> CreateCustomMessageViewForTest(
+ ArcNotificationItem* item,
+ const Notification& notification) {
+ auto message_view =
+ std::make_unique<ArcNotificationView>(item, notification);
+ message_view->content_view_->SetPreferredSize(gfx::Size(100, 100));
+ return message_view;
+ }
+
std::unique_ptr<Notification> notification_;
std::unique_ptr<ArcNotificationView> notification_view_;
@@ -285,28 +228,20 @@ class ArcNotificationViewTest : public views::ViewsTestBase {
DISALLOW_COPY_AND_ASSIGN(ArcNotificationViewTest);
};
-TEST_F(ArcNotificationViewTest, Background) {
- EXPECT_EQ(kBackgroundColor, GetBackgroundColor());
-}
-
TEST_F(ArcNotificationViewTest, Events) {
widget()->Show();
- contents_view()->RequestFocus();
- EXPECT_EQ(0, contents_view()->mouse_event_count());
gfx::Point cursor_location(1, 1);
- views::View::ConvertPointToWidget(contents_view(), &cursor_location);
- PerformClick(cursor_location);
- EXPECT_EQ(2, contents_view()->mouse_event_count());
-
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
- EXPECT_EQ(3, contents_view()->mouse_event_count());
-
- EXPECT_EQ(0, contents_view()->keyboard_event_count());
- KeyPress(ui::VKEY_A);
- EXPECT_EQ(1, contents_view()->keyboard_event_count());
+ views::View::ConvertPointToWidget(content_view(), &cursor_location);
+ EXPECT_EQ(content_view(),
+ widget()->GetRootView()->GetEventHandlerForPoint(cursor_location));
+
+ content_view()->RequestFocus();
+ ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
+ EXPECT_EQ(content_view(),
+ static_cast<ui::EventTargeter*>(
+ widget()->GetRootView()->GetEffectiveViewTargeter())
+ ->FindTargetForEvent(widget()->GetRootView(), &key_event));
}
TEST_F(ArcNotificationViewTest, SlideOut) {
@@ -316,6 +251,7 @@ TEST_F(ArcNotificationViewTest, SlideOut) {
std::string notification_id = notification()->id();
BeginScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
ScrollBy(-10);
EXPECT_FALSE(IsRemoved(notification_id));
EXPECT_EQ(-10.f, GetNotificationSlideAmount());
@@ -324,6 +260,7 @@ TEST_F(ArcNotificationViewTest, SlideOut) {
EXPECT_EQ(0.f, GetNotificationSlideAmount());
BeginScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
ScrollBy(-200);
EXPECT_FALSE(IsRemoved(notification_id));
EXPECT_EQ(-200.f, GetNotificationSlideAmount());
@@ -339,6 +276,7 @@ TEST_F(ArcNotificationViewTest, SlideOutNested) {
std::string notification_id = notification()->id();
BeginScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
ScrollBy(-10);
EXPECT_FALSE(IsRemoved(notification_id));
EXPECT_EQ(-10.f, GetNotificationSlideAmount());
@@ -347,6 +285,7 @@ TEST_F(ArcNotificationViewTest, SlideOutNested) {
EXPECT_EQ(0.f, GetNotificationSlideAmount());
BeginScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
ScrollBy(-200);
EXPECT_FALSE(IsRemoved(notification_id));
EXPECT_EQ(-200.f, GetNotificationSlideAmount());
@@ -367,10 +306,12 @@ TEST_F(ArcNotificationViewTest, SlideOutPinned) {
std::string notification_id = notification()->id();
BeginScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
ScrollBy(-200);
EXPECT_FALSE(IsRemoved(notification_id));
EXPECT_LT(-200.f, GetNotificationSlideAmount());
EndScroll();
+ EXPECT_EQ(0.f, GetNotificationSlideAmount());
EXPECT_FALSE(IsRemoved(notification_id));
}
@@ -378,9 +319,9 @@ TEST_F(ArcNotificationViewTest, SlideOutPinned) {
TEST_F(ArcNotificationViewTest, PressBackspaceKey) {
std::string notification_id = notification()->id();
- contents_view()->RequestFocus();
+ content_view()->RequestFocus();
- ui::InputMethod* input_method = contents_view()->GetInputMethod();
+ ui::InputMethod* input_method = content_view()->GetInputMethod();
ASSERT_TRUE(input_method);
TestTextInputClient text_input_client;
input_method->SetFocusedTextInputClient(&text_input_client);
@@ -395,9 +336,9 @@ TEST_F(ArcNotificationViewTest, PressBackspaceKey) {
TEST_F(ArcNotificationViewTest, PressBackspaceKeyOnEditBox) {
std::string notification_id = notification()->id();
- contents_view()->RequestFocus();
+ content_view()->RequestFocus();
- ui::InputMethod* input_method = contents_view()->GetInputMethod();
+ ui::InputMethod* input_method = content_view()->GetInputMethod();
ASSERT_TRUE(input_method);
TestTextInputClient text_input_client;
input_method->SetFocusedTextInputClient(&text_input_client);
@@ -419,13 +360,13 @@ TEST_F(ArcNotificationViewTest, ChangeContentHeight) {
EXPECT_EQ("360x100", size.ToString());
// Allow small notifications.
- contents_view()->SetPreferredSize(gfx::Size(10, 10));
+ content_view()->SetPreferredSize(gfx::Size(10, 10));
size = notification_view()->GetPreferredSize();
size.Enlarge(0, -notification_view()->GetInsets().height());
EXPECT_EQ("360x10", size.ToString());
// The long notification.
- contents_view()->SetPreferredSize(gfx::Size(1000, 1000));
+ content_view()->SetPreferredSize(gfx::Size(1000, 1000));
size = notification_view()->GetPreferredSize();
size.Enlarge(0, -notification_view()->GetInsets().height());
EXPECT_EQ("360x1000", size.ToString());
diff --git a/chromium/ui/arc/notification/mock_arc_notification_item.cc b/chromium/ui/arc/notification/mock_arc_notification_item.cc
new file mode 100644
index 00000000000..388d6c71bad
--- /dev/null
+++ b/chromium/ui/arc/notification/mock_arc_notification_item.cc
@@ -0,0 +1,85 @@
+// 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/arc/notification/mock_arc_notification_item.h"
+
+#include <utility>
+
+#include "base/bind_helpers.h"
+
+namespace arc {
+
+namespace {
+
+constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_";
+
+} // namespace
+
+MockArcNotificationItem::MockArcNotificationItem(
+ const std::string& notification_key)
+ : notification_key_(notification_key),
+ notification_id_(kNotificationIdPrefix + notification_key),
+ weak_factory_(this) {}
+
+MockArcNotificationItem::~MockArcNotificationItem() {
+ for (auto& observer : observers_)
+ observer.OnItemDestroying();
+}
+
+void MockArcNotificationItem::SetCloseCallback(
+ base::OnceClosure close_callback) {
+ close_callback_ = std::move(close_callback);
+}
+
+void MockArcNotificationItem::Close(bool by_user) {
+ count_close_++;
+
+ if (close_callback_)
+ base::ResetAndReturn(&close_callback_).Run();
+}
+
+const gfx::ImageSkia& MockArcNotificationItem::GetSnapshot() const {
+ return snapshot_;
+}
+
+const std::string& MockArcNotificationItem::GetNotificationKey() const {
+ return notification_key_;
+}
+
+const std::string& MockArcNotificationItem::GetNotificationId() const {
+ return notification_id_;
+}
+
+void MockArcNotificationItem::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MockArcNotificationItem::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+mojom::ArcNotificationType MockArcNotificationItem::GetNotificationType()
+ const {
+ return mojom::ArcNotificationType::SIMPLE;
+}
+
+mojom::ArcNotificationExpandState MockArcNotificationItem::GetExpandState()
+ const {
+ return mojom::ArcNotificationExpandState::FIXED_SIZE;
+}
+
+mojom::ArcNotificationShownContents MockArcNotificationItem::GetShownContents()
+ const {
+ return mojom::ArcNotificationShownContents::CONTENTS_SHOWN;
+}
+
+gfx::Rect MockArcNotificationItem::GetSwipeInputRect() const {
+ return gfx::Rect();
+}
+
+bool MockArcNotificationItem::IsManuallyExpandedOrCollapsed() const {
+ return false;
+}
+
+} // namespace arc
diff --git a/chromium/ui/arc/notification/mock_arc_notification_item.h b/chromium/ui/arc/notification/mock_arc_notification_item.h
new file mode 100644
index 00000000000..db2d22d055c
--- /dev/null
+++ b/chromium/ui/arc/notification/mock_arc_notification_item.h
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ARC_NOTIFICATION_MOCK_ARC_NOTIFICATION_ITEM_H_
+#define UI_ARC_NOTIFICATION_MOCK_ARC_NOTIFICATION_ITEM_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/observer_list.h"
+#include "ui/arc/notification/arc_notification_item.h"
+
+namespace arc {
+
+class MockArcNotificationItem : public ArcNotificationItem {
+ public:
+ MockArcNotificationItem(const std::string& notification_key);
+ ~MockArcNotificationItem() override;
+
+ // Methods for testing.
+ size_t count_close() { return count_close_; }
+ base::WeakPtr<MockArcNotificationItem> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ void SetCloseCallback(base::OnceClosure close_callback);
+
+ // Overriding methods for testing.
+ void Close(bool by_user) override;
+ const gfx::ImageSkia& GetSnapshot() const override;
+ const std::string& GetNotificationKey() const override;
+ const std::string& GetNotificationId() const override;
+
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+
+ // Overriding methods for returning dummy data or doing nothing.
+ void OnClosedFromAndroid() override {}
+ void Click() override {}
+ void ToggleExpansion() override {}
+ void OpenSettings() override {}
+ void IncrementWindowRefCount() override {}
+ void DecrementWindowRefCount() override {}
+ mojom::ArcNotificationType GetNotificationType() const override;
+ mojom::ArcNotificationExpandState GetExpandState() const override;
+ mojom::ArcNotificationShownContents GetShownContents() const override;
+ gfx::Rect GetSwipeInputRect() const override;
+
+ void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data,
+ const std::string& app_id) override {}
+ bool IsManuallyExpandedOrCollapsed() const override;
+
+ private:
+ std::string notification_key_;
+ std::string notification_id_;
+ gfx::ImageSkia snapshot_;
+ size_t count_close_ = 0;
+
+ base::ObserverList<Observer> observers_;
+ base::OnceClosure close_callback_;
+
+ base::WeakPtrFactory<MockArcNotificationItem> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockArcNotificationItem);
+};
+
+} // namespace arc
+
+#endif // UI_ARC_NOTIFICATION_MOCK_ARC_NOTIFICATION_ITEM_H_
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn
index 04f009d70b7..2f74c3a96c8 100644
--- a/chromium/ui/aura/BUILD.gn
+++ b/chromium/ui/aura/BUILD.gn
@@ -43,6 +43,8 @@ jumbo_component("aura") {
"mus/client_surface_embedder.h",
"mus/drag_drop_controller_host.h",
"mus/drag_drop_controller_mus.h",
+ "mus/embed_root.h",
+ "mus/embed_root_delegate.h",
"mus/focus_synchronizer.h",
"mus/focus_synchronizer_delegate.h",
"mus/focus_synchronizer_observer.h",
@@ -110,6 +112,7 @@ jumbo_component("aura") {
"mus/capture_synchronizer.cc",
"mus/client_surface_embedder.cc",
"mus/drag_drop_controller_mus.cc",
+ "mus/embed_root.cc",
"mus/focus_synchronizer.cc",
"mus/in_flight_change.cc",
"mus/input_method_mus.cc",
@@ -151,6 +154,7 @@ jumbo_component("aura") {
"//components/discardable_memory/client",
"//components/discardable_memory/public/interfaces",
"//components/viz/client",
+ "//components/viz/common",
"//components/viz/host",
"//components/viz/service",
"//gpu/ipc/client",
@@ -197,6 +201,10 @@ jumbo_component("aura") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
+ sources += [
+ "mus/platform_event_source_mus_ozone.cc",
+ "mus/platform_event_source_mus_ozone.h",
+ ]
}
if (is_android) {
@@ -258,6 +266,8 @@ jumbo_static_library("test_support") {
"test/ui_controls_factory_aura.h",
"test/window_event_dispatcher_test_api.cc",
"test/window_event_dispatcher_test_api.h",
+ "test/window_occlusion_tracker_test_api.cc",
+ "test/window_occlusion_tracker_test_api.h",
"test/window_test_api.cc",
"test/window_test_api.h",
]
@@ -276,6 +286,7 @@ jumbo_static_library("test_support") {
"//base/test:test_support",
"//cc:test_support",
"//components/viz/test:test_support",
+ "//services/service_manager/public/cpp",
"//services/ui/public/cpp/input_devices",
"//services/ui/public/interfaces",
"//skia",
@@ -348,6 +359,7 @@ executable("demo") {
test("aura_unittests") {
sources = [
+ "../compositor_extra/shadow_unittest.cc",
"gestures/gesture_recognizer_unittest.cc",
"hit_test_data_provider_aura_unittest.cc",
"mus/drag_drop_controller_mus_unittest.cc",
@@ -360,6 +372,7 @@ test("aura_unittests") {
"mus/window_port_mus_unittest.cc",
"mus/window_tree_client_unittest.cc",
"mus/window_tree_host_mus_unittest.cc",
+ "test/aura_test_suite.h",
"test/run_all_unittests.cc",
"window_event_dispatcher_unittest.cc",
"window_occlusion_tracker_unittest.cc",
@@ -373,7 +386,7 @@ test("aura_unittests") {
"//base/test:test_support",
"//components/viz/client",
"//mojo/common",
- "//mojo/edk/system",
+ "//mojo/edk",
"//net",
"//services/ui/common:task_runner_test_base",
"//services/ui/public/cpp",
@@ -381,6 +394,7 @@ test("aura_unittests") {
"//testing/gtest",
"//ui/base:test_support",
"//ui/compositor:test_support",
+ "//ui/compositor_extra",
"//ui/display:test_support",
"//ui/events:gesture_detection",
"//ui/events:test_support",
diff --git a/chromium/ui/aura/OWNERS b/chromium/ui/aura/OWNERS
index ff3f87628e1..7958658c4cd 100644
--- a/chromium/ui/aura/OWNERS
+++ b/chromium/ui/aura/OWNERS
@@ -1,5 +1,5 @@
sky@chromium.org
sadrul@chromium.org
-per-file *x11.cc=erg@chromium.org
-per-file *x11.h=erg@chromium.org
+per-file *x11.cc=thomasanderson@chromium.org
+per-file *x11.h=thomasanderson@chromium.org
diff --git a/chromium/ui/aura/client/aura_constants.cc b/chromium/ui/aura/client/aura_constants.cc
index c171556d287..e4217f53689 100644
--- a/chromium/ui/aura/client/aura_constants.cc
+++ b/chromium/ui/aura/client/aura_constants.cc
@@ -47,7 +47,7 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kConstrainedWindowKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCreatedByUserGesture, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(FocusClient*, kFocusClientKey, nullptr);
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHasBackdrop, false);
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHasOverviewIcon, false);
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImmersiveFullscreenKey, false);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMinimumSize, nullptr);
diff --git a/chromium/ui/aura/client/aura_constants.h b/chromium/ui/aura/client/aura_constants.h
index f0f8b6cbf53..b2b1ffe3a11 100644
--- a/chromium/ui/aura/client/aura_constants.h
+++ b/chromium/ui/aura/client/aura_constants.h
@@ -77,9 +77,9 @@ AURA_EXPORT extern const WindowProperty<bool>* const kDrawAttentionKey;
// A property key to store the focus client on the window.
AURA_EXPORT extern const WindowProperty<FocusClient*>* const kFocusClientKey;
-// A bool property key to specify if the window should have a backdrop window
-// (typically black) that covers the desktop behind the window.
-AURA_EXPORT extern const WindowProperty<bool>* const kHasBackdrop;
+// A bool property key to specify if the window has a icon set for displaying in
+// overivew mode.
+AURA_EXPORT extern const WindowProperty<bool>* const kHasOverviewIcon;
// A property key to store the host window of a window. This lets
// WebContentsViews find the windows that should constrain NPAPI plugins.
diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc
index b62fcc15aba..b32f9f5ddbf 100644
--- a/chromium/ui/aura/env.cc
+++ b/chromium/ui/aura/env.cc
@@ -6,7 +6,6 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_local.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/aura/client/aura_constants.h"
@@ -25,8 +24,6 @@
#include "ui/events/platform/platform_event_source.h"
#if defined(USE_OZONE)
-#include "ui/gfx/client_native_pixmap_factory.h"
-#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#endif
@@ -50,10 +47,6 @@ Env::~Env() {
if (is_override_input_injector_factory_)
ui::SetSystemInputInjectorFactory(nullptr);
-#if defined(USE_OZONE)
- gfx::ClientNativePixmapFactory::ResetInstance();
-#endif
-
for (EnvObserver& observer : observers_)
observer.OnWillDestroyEnv();
@@ -158,6 +151,9 @@ void Env::ScheduleEmbed(
////////////////////////////////////////////////////////////////////////////////
// Env, private:
+// static
+bool Env::initial_throttle_input_on_resize_ = true;
+
Env::Env(Mode mode)
: mode_(mode),
env_controller_(new EnvInputStateController),
@@ -172,10 +168,6 @@ Env::Env(Mode mode)
}
void Env::Init() {
-#if defined(USE_OZONE)
- ui::CreateClientNativePixmapFactoryOzone();
- DCHECK(gfx::ClientNativePixmapFactory::GetInstance());
-#endif
if (mode_ == Mode::MUS) {
EnableMusOSExchangeDataProvider();
EnableMusOverrideInputInjector();
diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h
index bc615fdb3a1..7167a9f1655 100644
--- a/chromium/ui/aura/env.h
+++ b/chromium/ui/aura/env.h
@@ -18,10 +18,6 @@
#include "ui/events/system_input_injector.h"
#include "ui/gfx/geometry/point.h"
-#if defined(USE_OZONE)
-#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
-#endif
-
namespace base {
class UnguessableToken;
}
@@ -112,6 +108,12 @@ class AURA_EXPORT Env : public ui::EventTarget,
}
ui::ContextFactory* context_factory() { return context_factory_; }
+ // Sets |initial_throttle_input_on_resize| the next time Env is created. This
+ // is only useful in tests that need to disable input resize.
+ static void set_initial_throttle_input_on_resize_for_testing(
+ bool throttle_input) {
+ initial_throttle_input_on_resize_ = throttle_input;
+ }
void set_throttle_input_on_resize_for_testing(bool throttle_input) {
throttle_input_on_resize_ = throttle_input;
}
@@ -215,7 +217,8 @@ class AURA_EXPORT Env : public ui::EventTarget,
// creating a different WindowPort implementation.
bool in_mus_shutdown_ = false;
- bool throttle_input_on_resize_ = true;
+ static bool initial_throttle_input_on_resize_;
+ bool throttle_input_on_resize_ = initial_throttle_input_on_resize_;
DISALLOW_COPY_AND_ASSIGN(Env);
};
diff --git a/chromium/ui/aura/event_injector.cc b/chromium/ui/aura/event_injector.cc
index f13e06742c1..c9d9242b60d 100644
--- a/chromium/ui/aura/event_injector.cc
+++ b/chromium/ui/aura/event_injector.cc
@@ -55,13 +55,13 @@ ui::EventDispatchDetails EventInjector::Inject(WindowTreeHost* host,
event->AsLocatedEvent()->location_f());
}
- if (!remote_event_dispatcher_) {
+ if (!event_injector_) {
env->window_tree_client_->connector()->BindInterface(
- ui::mojom::kServiceName, &remote_event_dispatcher_);
+ ui::mojom::kServiceName, &event_injector_);
}
- remote_event_dispatcher_->DispatchEvent(
+ event_injector_->InjectEvent(
host->GetDisplayId(), MapEvent(*event),
- base::Bind([](bool result) { DCHECK(result); }));
+ base::BindOnce([](bool result) { DCHECK(result); }));
return ui::EventDispatchDetails();
}
diff --git a/chromium/ui/aura/event_injector.h b/chromium/ui/aura/event_injector.h
index acfcf1cd2c3..bc336047f51 100644
--- a/chromium/ui/aura/event_injector.h
+++ b/chromium/ui/aura/event_injector.h
@@ -5,7 +5,7 @@
#ifndef UI_AURA_EVENT_INJECTOR_H_
#define UI_AURA_EVENT_INJECTOR_H_
-#include "services/ui/public/interfaces/remote_event_dispatcher.mojom.h"
+#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "ui/aura/aura_export.h"
namespace ui {
@@ -28,7 +28,7 @@ class AURA_EXPORT EventInjector {
ui::EventDispatchDetails Inject(WindowTreeHost* host, ui::Event* event);
private:
- ui::mojom::RemoteEventDispatcherPtr remote_event_dispatcher_;
+ ui::mojom::EventInjectorPtr event_injector_;
DISALLOW_COPY_AND_ASSIGN(EventInjector);
};
diff --git a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
index 827c9dca4c2..39c305eaae4 100644
--- a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
diff --git a/chromium/ui/aura/hit_test_data_provider_aura.cc b/chromium/ui/aura/hit_test_data_provider_aura.cc
index 0f7600aae12..0f96540ac90 100644
--- a/chromium/ui/aura/hit_test_data_provider_aura.cc
+++ b/chromium/ui/aura/hit_test_data_provider_aura.cc
@@ -22,13 +22,10 @@ viz::mojom::HitTestRegionPtr CreateHitTestRegion(const aura::Window* window,
hit_test_region->frame_sink_id = window->GetFrameSinkId();
// Checking |layer| may not be correct, since the actual layer that embeds
// the surface may be a descendent of |layer|, instead of |layer| itself.
- if (window->IsEmbeddingClient()) {
- DCHECK(window->GetLocalSurfaceId().is_valid());
- hit_test_region->local_surface_id = window->GetLocalSurfaceId();
+ if (window->IsEmbeddingClient())
hit_test_region->flags = flags | viz::mojom::kHitTestChildSurface;
- } else {
+ else
hit_test_region->flags = flags | viz::mojom::kHitTestMine;
- }
hit_test_region->rect = rect;
hit_test_region->transform = layer->transform();
diff --git a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc b/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc
index 96a6d82decd..4b0363e6177 100644
--- a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc
+++ b/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc
@@ -15,21 +15,6 @@ namespace aura {
namespace {
-const int kMouseInset = -5;
-const int kTouchInset = -10;
-
-// Custom WindowTargeter that expands hit-test regions of child windows.
-class TestWindowTargeter : public WindowTargeter {
- public:
- TestWindowTargeter() {
- SetInsets(gfx::Insets(kMouseInset), gfx::Insets(kTouchInset));
- }
- ~TestWindowTargeter() override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestWindowTargeter);
-};
-
// Custom WindowTargeter that replaces hit-test area on a window with a frame
// rectangle and a hole in the middle 1/3.
// ----------------------
@@ -189,7 +174,12 @@ TEST_F(HitTestDataProviderAuraTest, Stacking) {
// Tests that the hit-test regions get expanded with a custom event targeter.
TEST_F(HitTestDataProviderAuraTest, CustomTargeter) {
- window3()->SetEventTargeter(std::make_unique<TestWindowTargeter>());
+ constexpr int kMouseInset = -5;
+ constexpr int kTouchInset = -10;
+ auto targeter = std::make_unique<aura::WindowTargeter>();
+ targeter->SetInsets(gfx::Insets(kMouseInset), gfx::Insets(kTouchInset));
+ window3()->SetEventTargeter(std::move(targeter));
+
window2()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 2));
const auto hit_test_data =
hit_test_data_provider()->GetHitTestData(compositor_frame_);
diff --git a/chromium/ui/aura/local/window_port_local.cc b/chromium/ui/aura/local/window_port_local.cc
index 787fbc5e7cc..40abe881763 100644
--- a/chromium/ui/aura/local/window_port_local.cc
+++ b/chromium/ui/aura/local/window_port_local.cc
@@ -140,6 +140,16 @@ void WindowPortLocal::AllocateLocalSurfaceId() {
frame_sink_->SetLocalSurfaceId(local_surface_id_);
}
+bool WindowPortLocal::IsLocalSurfaceIdAllocationSuppressed() const {
+ return parent_local_surface_id_allocator_.is_allocation_suppressed();
+}
+
+viz::ScopedSurfaceIdAllocator WindowPortLocal::GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) {
+ return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_,
+ std::move(allocation_task));
+}
+
const viz::LocalSurfaceId& WindowPortLocal::GetLocalSurfaceId() {
if (!local_surface_id_.is_valid())
AllocateLocalSurfaceId();
@@ -153,7 +163,8 @@ void WindowPortLocal::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_);
window_->layer()->SetShowPrimarySurface(
surface_info.id(), window_->bounds().size(), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(),
+ false /* stretch_content_to_fill_bounds */);
window_->layer()->SetFallbackSurfaceId(surface_info.id());
}
diff --git a/chromium/ui/aura/local/window_port_local.h b/chromium/ui/aura/local/window_port_local.h
index 58abd724537..8c2b4b35ac8 100644
--- a/chromium/ui/aura/local/window_port_local.h
+++ b/chromium/ui/aura/local/window_port_local.h
@@ -47,6 +47,9 @@ class AURA_EXPORT WindowPortLocal : public WindowPort {
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
+ bool IsLocalSurfaceIdAllocationSuppressed() const override;
+ viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) override;
const viz::LocalSurfaceId& GetLocalSurfaceId() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
diff --git a/chromium/ui/aura/mus/client_surface_embedder.cc b/chromium/ui/aura/mus/client_surface_embedder.cc
index 7863b68f365..74f31fd2e70 100644
--- a/chromium/ui/aura/mus/client_surface_embedder.cc
+++ b/chromium/ui/aura/mus/client_surface_embedder.cc
@@ -4,7 +4,6 @@
#include "ui/aura/mus/client_surface_embedder.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/dip_util.h"
@@ -37,7 +36,8 @@ void ClientSurfaceEmbedder::SetPrimarySurfaceId(
const viz::SurfaceId& surface_id) {
surface_layer_->SetShowPrimarySurface(
surface_id, window_->bounds().size(), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(),
+ false /* stretch_content_to_fill_bounds */);
}
void ClientSurfaceEmbedder::SetFallbackSurfaceInfo(
diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus.cc b/chromium/ui/aura/mus/drag_drop_controller_mus.cc
index 532b0364807..fa518e272af 100644
--- a/chromium/ui/aura/mus/drag_drop_controller_mus.cc
+++ b/chromium/ui/aura/mus/drag_drop_controller_mus.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/auto_reset.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "mojo/public/cpp/bindings/map.h"
diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc b/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
index d5be3749b80..24227cf7076 100644
--- a/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
+++ b/chromium/ui/aura/mus/drag_drop_controller_mus_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "base/callback_forward.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/ui/aura/mus/embed_root.cc b/chromium/ui/aura/mus/embed_root.cc
new file mode 100644
index 00000000000..058bacaaeb4
--- /dev/null
+++ b/chromium/ui/aura/mus/embed_root.cc
@@ -0,0 +1,133 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/mus/embed_root.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/mus/embed_root_delegate.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/aura/window_tree_host.h"
+
+namespace aura {
+namespace {
+
+// FocusClient implementation used for embedded windows. This has minimal
+// checks as to what can get focus.
+class EmbeddedFocusClient : public client::FocusClient, public WindowObserver {
+ public:
+ explicit EmbeddedFocusClient(Window* root) : root_(root) {
+ client::SetFocusClient(root, this);
+ }
+
+ ~EmbeddedFocusClient() override {
+ client::SetFocusClient(root_, nullptr);
+ if (focused_window_)
+ focused_window_->RemoveObserver(this);
+ }
+
+ // client::FocusClient:
+ void AddObserver(client::FocusChangeObserver* observer) override {
+ observers_.AddObserver(observer);
+ }
+ void RemoveObserver(client::FocusChangeObserver* observer) override {
+ observers_.RemoveObserver(observer);
+ }
+ void FocusWindow(Window* window) override {
+ if (IsValidWindowForFocus(window) && window != GetFocusedWindow())
+ FocusWindowImpl(window);
+ }
+ void ResetFocusWithinActiveWindow(Window* window) override {
+ // This is never called in the embedding case.
+ NOTREACHED();
+ }
+ Window* GetFocusedWindow() override { return focused_window_; }
+
+ private:
+ bool IsValidWindowForFocus(Window* window) const {
+ return !window || (root_->Contains(window) && window->CanFocus());
+ }
+
+ void FocusWindowImpl(Window* window) {
+ Window* previously_focused_window = focused_window_;
+
+ if (previously_focused_window)
+ previously_focused_window->RemoveObserver(this);
+ focused_window_ = window;
+ if (focused_window_)
+ focused_window_->AddObserver(this);
+
+ WindowTracker window_tracker;
+ if (previously_focused_window)
+ window_tracker.Add(previously_focused_window);
+ for (auto& observer : observers_) {
+ observer.OnWindowFocused(
+ focused_window_, window_tracker.Contains(previously_focused_window)
+ ? previously_focused_window
+ : nullptr);
+ }
+ }
+
+ // WindowObserver:
+ void OnWindowDestroying(Window* window) override {
+ DCHECK_EQ(window, focused_window_);
+ }
+
+ // Root of the hierarchy this is the FocusClient for.
+ Window* const root_;
+
+ Window* focused_window_ = nullptr;
+
+ base::ObserverList<client::FocusChangeObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedFocusClient);
+};
+
+} // namespace
+
+EmbedRoot::~EmbedRoot() {
+ window_tree_client_->OnEmbedRootDestroyed(this);
+ // Makes use of window_tree_host_->window(), so needs to be destroyed before
+ // |window_tree_host_|.
+ focus_client_.reset();
+}
+
+Window* EmbedRoot::window() {
+ return window_tree_host_ ? window_tree_host_->window() : nullptr;
+}
+
+EmbedRoot::EmbedRoot(WindowTreeClient* window_tree_client,
+ EmbedRootDelegate* delegate,
+ ui::ClientSpecificId window_id)
+ : window_tree_client_(window_tree_client),
+ delegate_(delegate),
+ weak_factory_(this) {
+ window_tree_client_->tree_->ScheduleEmbedForExistingClient(
+ window_id, base::BindOnce(&EmbedRoot::OnScheduledEmbedForExistingClient,
+ weak_factory_.GetWeakPtr()));
+}
+
+void EmbedRoot::OnScheduledEmbedForExistingClient(
+ const base::UnguessableToken& token) {
+ token_ = token;
+ delegate_->OnEmbedTokenAvailable(token);
+}
+
+void EmbedRoot::OnEmbed(std::unique_ptr<WindowTreeHost> window_tree_host) {
+ focus_client_ =
+ std::make_unique<EmbeddedFocusClient>(window_tree_host->window());
+ window_tree_host_ = std::move(window_tree_host);
+ delegate_->OnEmbed(window());
+}
+
+void EmbedRoot::OnUnembed() {
+ delegate_->OnUnembed();
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/mus/embed_root.h b/chromium/ui/aura/mus/embed_root.h
new file mode 100644
index 00000000000..f1aa46dffb7
--- /dev/null
+++ b/chromium/ui/aura/mus/embed_root.h
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_MUS_EMBED_ROOT_H_
+#define UI_AURA_MUS_EMBED_ROOT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/unguessable_token.h"
+#include "services/ui/common/types.h"
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+
+class EmbedRootDelegate;
+class Window;
+class WindowTreeClient;
+class WindowTreeHost;
+
+namespace client {
+class FocusClient;
+}
+
+// EmbedRoot represents a secondary embedding from the perspective of the
+// embedded client. More specifically an EmbedRoot allows a remote client to
+// embed this client in one of the remote client's Windows.
+//
+// See EmbedRootDelegate for details on how to use.
+//
+// EmbedRoot is created by way of WindowTreeClient::CreateEmbedRoot().
+class AURA_EXPORT EmbedRoot {
+ public:
+ ~EmbedRoot();
+
+ // Token for the embedding. Empty until OnEmbedTokenAvailable() is called on
+ // the delegate.
+ const base::UnguessableToken& token() const { return token_; }
+
+ // Window for the embedding, null until the OnEmbed() is called on the
+ // delegate.
+ aura::Window* window();
+
+ private:
+ friend class WindowTreeClient;
+ friend class WindowTreeClientPrivate;
+
+ EmbedRoot(WindowTreeClient* window_tree_client,
+ EmbedRootDelegate* delegate,
+ ui::ClientSpecificId window_id);
+
+ // Callback from WindowTreeClient once the token has been determined.
+ void OnScheduledEmbedForExistingClient(const base::UnguessableToken& token);
+
+ // Called from WindowTreeClient when the embedding is established.
+ void OnEmbed(std::unique_ptr<WindowTreeHost> window_tree_host);
+
+ // Called from WindowTreeClient when unembedded from the Window.
+ void OnUnembed();
+
+ WindowTreeClient* window_tree_client_;
+
+ EmbedRootDelegate* delegate_;
+
+ base::UnguessableToken token_;
+
+ std::unique_ptr<client::FocusClient> focus_client_;
+
+ std::unique_ptr<WindowTreeHost> window_tree_host_;
+
+ base::WeakPtrFactory<EmbedRoot> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbedRoot);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_MUS_EMBED_ROOT_H_
diff --git a/chromium/ui/aura/mus/embed_root_delegate.h b/chromium/ui/aura/mus/embed_root_delegate.h
new file mode 100644
index 00000000000..e2c6cd49e77
--- /dev/null
+++ b/chromium/ui/aura/mus/embed_root_delegate.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_MUS_EMBED_ROOT_DELEGATE_H_
+#define UI_AURA_MUS_EMBED_ROOT_DELEGATE_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace base {
+class UnguessableToken;
+}
+
+namespace aura {
+
+class Window;
+
+// Called from EmbedRoot at key points during the life-time of the embedding.
+class AURA_EXPORT EmbedRootDelegate {
+ public:
+ // Called first in the process of establishing an embedding. |token| is used
+ // by a remote client to embed this client in one of the remote client's
+ // windows. The delegate will typically pass the supplied token over mojo and
+ // the remote client will then call WindowTreeClient::EmbedUsingToken().
+ virtual void OnEmbedTokenAvailable(const base::UnguessableToken& token) = 0;
+
+ // Called once the embedding has been established. |window| is the root of
+ // the embedding and owned by the remote client.
+ virtual void OnEmbed(Window* window) = 0;
+
+ // Called if the remote client embeds another client in the root. The delegate
+ // will typically delete the EmbedRoot shortly after receiving this.
+ virtual void OnUnembed() = 0;
+
+ protected:
+ virtual ~EmbedRootDelegate() {}
+};
+
+} // namespace aura
+
+#endif // UI_AURA_MUS_EMBED_ROOT_DELEGATE_H_
diff --git a/chromium/ui/aura/mus/focus_synchronizer.h b/chromium/ui/aura/mus/focus_synchronizer.h
index b2908cb7ce9..ebacfcea6b4 100644
--- a/chromium/ui/aura/mus/focus_synchronizer.h
+++ b/chromium/ui/aura/mus/focus_synchronizer.h
@@ -27,7 +27,7 @@ namespace client {
class FocusClient;
}
-// FocusSynchronizer is resonsible for keeping focus in sync between aura
+// FocusSynchronizer is responsible for keeping focus in sync between aura
// and the mus server. FocusSynchronizer may be configured in two distinct
// ways:
// . SetSingletonFocusClient(). Use this when a single FocusClient is shared
diff --git a/chromium/ui/aura/mus/input_method_mus.cc b/chromium/ui/aura/mus/input_method_mus.cc
index bfd2555a828..ef87de618fa 100644
--- a/chromium/ui/aura/mus/input_method_mus.cc
+++ b/chromium/ui/aura/mus/input_method_mus.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#include "services/ui/public/interfaces/ime/ime.mojom.h"
#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
@@ -45,7 +44,7 @@ void InputMethodMus::Init(service_manager::Connector* connector) {
ui::EventDispatchDetails InputMethodMus::DispatchKeyEvent(
ui::KeyEvent* event,
- std::unique_ptr<EventResultCallback> ack_callback) {
+ EventResultCallback ack_callback) {
DCHECK(event->type() == ui::ET_KEY_PRESSED ||
event->type() == ui::ET_KEY_RELEASED);
@@ -53,8 +52,9 @@ ui::EventDispatchDetails InputMethodMus::DispatchKeyEvent(
if (!GetTextInputClient()) {
ui::EventDispatchDetails dispatch_details = DispatchKeyEventPostIME(event);
if (ack_callback) {
- ack_callback->Run(event->handled() ? EventResult::HANDLED
- : EventResult::UNHANDLED);
+ std::move(ack_callback)
+ .Run(event->handled() ? EventResult::HANDLED
+ : EventResult::UNHANDLED);
}
return dispatch_details;
}
@@ -75,15 +75,9 @@ void InputMethodMus::OnBlur() {
UpdateTextInputType();
}
-bool InputMethodMus::OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) {
- // This method is not called on non-Windows platforms. See the comments for
- // ui::InputMethod::OnUntranslatedIMEMessage().
- return false;
-}
-
ui::EventDispatchDetails InputMethodMus::DispatchKeyEvent(ui::KeyEvent* event) {
- ui::EventDispatchDetails dispatch_details = DispatchKeyEvent(event, nullptr);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchKeyEvent(event, EventResultCallback());
// Mark the event as handled so that EventGenerator doesn't attempt to
// deliver event as well.
event->SetHandled();
@@ -130,7 +124,7 @@ bool InputMethodMus::IsCandidatePopupOpen() const {
ui::EventDispatchDetails InputMethodMus::SendKeyEventToInputMethod(
const ui::KeyEvent& event,
- std::unique_ptr<EventResultCallback> ack_callback) {
+ EventResultCallback ack_callback) {
if (!input_method_) {
// This code path is hit in tests that don't connect to the server.
DCHECK(!ack_callback);
@@ -143,8 +137,8 @@ ui::EventDispatchDetails InputMethodMus::SendKeyEventToInputMethod(
pending_callbacks_.push_back(std::move(ack_callback));
input_method_->ProcessKeyEvent(
ui::Event::Clone(event),
- base::Bind(&InputMethodMus::ProcessKeyEventCallback,
- base::Unretained(this), event));
+ base::BindOnce(&InputMethodMus::ProcessKeyEventCallback,
+ base::Unretained(this), event));
return ui::EventDispatchDetails();
}
@@ -197,9 +191,9 @@ void InputMethodMus::UpdateTextInputType() {
}
void InputMethodMus::AckPendingCallbacksUnhandled() {
- for (auto& callback_ptr : pending_callbacks_) {
- if (callback_ptr)
- callback_ptr->Run(EventResult::UNHANDLED);
+ for (auto& callback : pending_callbacks_) {
+ if (callback)
+ std::move(callback).Run(EventResult::UNHANDLED);
}
pending_callbacks_.clear();
}
@@ -210,15 +204,16 @@ void InputMethodMus::ProcessKeyEventCallback(
// Remove the callback as DispatchKeyEventPostIME() may lead to calling
// AckPendingCallbacksUnhandled(), which mutates |pending_callbacks_|.
DCHECK(!pending_callbacks_.empty());
- std::unique_ptr<EventResultCallback> ack_callback =
- std::move(pending_callbacks_.front());
+ EventResultCallback ack_callback = std::move(pending_callbacks_.front());
pending_callbacks_.pop_front();
// |ack_callback| can be null if the standard form of DispatchKeyEvent() is
// called instead of the version which provides a callback. In mus+ash we
// use the version with callback, but some unittests use the standard form.
- if (ack_callback)
- ack_callback->Run(handled ? EventResult::HANDLED : EventResult::UNHANDLED);
+ if (ack_callback) {
+ std::move(ack_callback)
+ .Run(handled ? EventResult::HANDLED : EventResult::UNHANDLED);
+ }
}
} // namespace aura
diff --git a/chromium/ui/aura/mus/input_method_mus.h b/chromium/ui/aura/mus/input_method_mus.h
index 027c7331ef1..8a4956469d1 100644
--- a/chromium/ui/aura/mus/input_method_mus.h
+++ b/chromium/ui/aura/mus/input_method_mus.h
@@ -27,21 +27,19 @@ class Window;
class AURA_EXPORT InputMethodMus : public ui::InputMethodBase {
public:
- using EventResultCallback = base::Callback<void(ui::mojom::EventResult)>;
+ using EventResultCallback = base::OnceCallback<void(ui::mojom::EventResult)>;
InputMethodMus(ui::internal::InputMethodDelegate* delegate, Window* window);
~InputMethodMus() override;
void Init(service_manager::Connector* connector);
- ui::EventDispatchDetails DispatchKeyEvent(
- ui::KeyEvent* event,
- std::unique_ptr<EventResultCallback> ack_callback) WARN_UNUSED_RESULT;
+ ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event,
+ EventResultCallback ack_callback)
+ WARN_UNUSED_RESULT;
// Overridden from ui::InputMethod:
void OnFocus() override;
void OnBlur() override;
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnTextInputTypeChanged(const ui::TextInputClient* client) override;
void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
@@ -56,7 +54,7 @@ class AURA_EXPORT InputMethodMus : public ui::InputMethodBase {
// Called from DispatchKeyEvent() to call to the InputMethod.
ui::EventDispatchDetails SendKeyEventToInputMethod(
const ui::KeyEvent& event,
- std::unique_ptr<EventResultCallback> ack_callback) WARN_UNUSED_RESULT;
+ EventResultCallback ack_callback) WARN_UNUSED_RESULT;
// Overridden from ui::InputMethodBase:
void OnDidChangeFocusedClient(ui::TextInputClient* focused_before,
@@ -89,7 +87,7 @@ class AURA_EXPORT InputMethodMus : public ui::InputMethodBase {
// Callbacks supplied to DispatchKeyEvent() are added here while awaiting
// the response from the server. These are removed when the response is
// received (ProcessKeyEventCallback()).
- base::circular_deque<std::unique_ptr<EventResultCallback>> pending_callbacks_;
+ base::circular_deque<EventResultCallback> pending_callbacks_;
DISALLOW_COPY_AND_ASSIGN(InputMethodMus);
};
diff --git a/chromium/ui/aura/mus/input_method_mus_unittest.cc b/chromium/ui/aura/mus/input_method_mus_unittest.cc
index 582e0a2b41a..fa7cefb2614 100644
--- a/chromium/ui/aura/mus/input_method_mus_unittest.cc
+++ b/chromium/ui/aura/mus/input_method_mus_unittest.cc
@@ -33,7 +33,7 @@ class TestInputMethodDelegate : public ui::internal::InputMethodDelegate {
using ProcessKeyEventCallback = base::OnceCallback<void(bool)>;
using ProcessKeyEventCallbacks = std::vector<ProcessKeyEventCallback>;
-using EventResultCallback = base::Callback<void(ui::mojom::EventResult)>;
+using EventResultCallback = base::OnceCallback<void(ui::mojom::EventResult)>;
// InputMethod implementation that queues up the callbacks supplied to
// ProcessKeyEvent().
@@ -104,9 +104,8 @@ TEST_F(InputMethodMusTest, PendingCallbackRunFromDestruction) {
TestInputMethod test_input_method;
InputMethodMusTestApi::SetInputMethod(&input_method_mus,
&test_input_method);
- std::unique_ptr<EventResultCallback> callback =
- std::make_unique<EventResultCallback>(base::Bind(
- &RunFunctionWithEventResult, &was_event_result_callback_run));
+ EventResultCallback callback = base::BindOnce(
+ &RunFunctionWithEventResult, &was_event_result_callback_run);
ui::EventDispatchDetails details =
InputMethodMusTestApi::CallSendKeyEventToInputMethod(
@@ -118,7 +117,7 @@ TEST_F(InputMethodMusTest, PendingCallbackRunFromDestruction) {
// Add a null callback as well, to make sure null is deal with.
details = InputMethodMusTestApi::CallSendKeyEventToInputMethod(
&input_method_mus, ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0),
- nullptr);
+ InputMethodMus::EventResultCallback());
ASSERT_TRUE(!details.dispatcher_destroyed && !details.target_destroyed);
// The event should have been queued.
EXPECT_EQ(2u, test_input_method.process_key_event_callbacks()->size());
@@ -140,9 +139,8 @@ TEST_F(InputMethodMusTest, PendingCallbackRunFromOnDidChangeFocusedClient) {
InputMethodMus input_method_mus(&input_method_delegate, &window);
TestInputMethod test_input_method;
InputMethodMusTestApi::SetInputMethod(&input_method_mus, &test_input_method);
- std::unique_ptr<EventResultCallback> callback =
- std::make_unique<EventResultCallback>(base::Bind(
- &RunFunctionWithEventResult, &was_event_result_callback_run));
+ EventResultCallback callback = base::BindOnce(&RunFunctionWithEventResult,
+ &was_event_result_callback_run);
ui::EventDispatchDetails details =
InputMethodMusTestApi::CallSendKeyEventToInputMethod(
&input_method_mus,
@@ -206,9 +204,8 @@ TEST_F(InputMethodMusTest, ChangeTextInputTypeWhileProcessingCallback) {
&test_input_client);
TestInputMethod test_input_method;
InputMethodMusTestApi::SetInputMethod(&input_method_mus, &test_input_method);
- std::unique_ptr<EventResultCallback> callback =
- std::make_unique<EventResultCallback>(base::Bind(
- &RunFunctionWithEventResult, &was_event_result_callback_run));
+ EventResultCallback callback = base::BindOnce(&RunFunctionWithEventResult,
+ &was_event_result_callback_run);
const ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0);
ui::EventDispatchDetails details =
InputMethodMusTestApi::CallSendKeyEventToInputMethod(
diff --git a/chromium/ui/aura/mus/mus_context_factory.cc b/chromium/ui/aura/mus/mus_context_factory.cc
index f2b4dc0c60e..73badbb19db 100644
--- a/chromium/ui/aura/mus/mus_context_factory.cc
+++ b/chromium/ui/aura/mus/mus_context_factory.cc
@@ -5,7 +5,6 @@
#include "ui/aura/mus/mus_context_factory.h"
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "cc/base/switches.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/host/renderer_settings_creation.h"
diff --git a/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc b/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
index 7ce7c71f376..225a515a754 100644
--- a/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
+++ b/chromium/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
diff --git a/chromium/ui/aura/mus/platform_event_source_mus_ozone.cc b/chromium/ui/aura/mus/platform_event_source_mus_ozone.cc
new file mode 100644
index 00000000000..dfd4133673b
--- /dev/null
+++ b/chromium/ui/aura/mus/platform_event_source_mus_ozone.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/mus/platform_event_source_mus_ozone.h"
+
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_observer.h"
+
+namespace aura {
+
+PlatformEventSourceMus::PlatformEventSourceMus() = default;
+
+PlatformEventSourceMus::~PlatformEventSourceMus() = default;
+
+void PlatformEventSourceMus::OnWillProcessEvent(ui::Event* event) {
+ for (ui::PlatformEventObserver& observer : observers())
+ observer.WillProcessEvent(event);
+}
+
+void PlatformEventSourceMus::OnDidProcessEvent(ui::Event* event) {
+ for (ui::PlatformEventObserver& observer : observers())
+ observer.DidProcessEvent(event);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/mus/platform_event_source_mus_ozone.h b/chromium/ui/aura/mus/platform_event_source_mus_ozone.h
new file mode 100644
index 00000000000..8557688c8d7
--- /dev/null
+++ b/chromium/ui/aura/mus/platform_event_source_mus_ozone.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_MUS_PLATFORM_EVENT_SOURCE_MUS_OZONE_H_
+#define UI_AURA_MUS_PLATFORM_EVENT_SOURCE_MUS_OZONE_H_
+
+#include "ui/events/platform/platform_event_source.h"
+
+namespace ui {
+class Event;
+}
+
+namespace aura {
+
+// PlatformEventSource implementation for mus with ozone. WindowTreeClient owns
+// and installs this. WindowTreeClient calls this to notify observers as
+// necessary.
+class PlatformEventSourceMus : public ui::PlatformEventSource {
+ public:
+ PlatformEventSourceMus();
+ ~PlatformEventSourceMus() override;
+
+ // These two functions are called from WindowTreeClient before/after
+ // dispatching events. They forward to observers.
+ void OnWillProcessEvent(ui::Event* event);
+ void OnDidProcessEvent(ui::Event* event);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PlatformEventSourceMus);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_MUS_PLATFORM_EVENT_SOURCE_MUS_OZONE_H_
diff --git a/chromium/ui/aura/mus/property_converter.cc b/chromium/ui/aura/mus/property_converter.cc
index 7a0a67e0177..ae2ce3a787d 100644
--- a/chromium/ui/aura/mus/property_converter.cc
+++ b/chromium/ui/aura/mus/property_converter.cc
@@ -4,7 +4,6 @@
#include "ui/aura/mus/property_converter.h"
-#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
diff --git a/chromium/ui/aura/mus/user_activity_forwarder_unittest.cc b/chromium/ui/aura/mus/user_activity_forwarder_unittest.cc
index 9d011c0e723..249cc0ad150 100644
--- a/chromium/ui/aura/mus/user_activity_forwarder_unittest.cc
+++ b/chromium/ui/aura/mus/user_activity_forwarder_unittest.cc
@@ -8,7 +8,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/ui/common/task_runner_test_base.h"
diff --git a/chromium/ui/aura/mus/window_port_mus.cc b/chromium/ui/aura/mus/window_port_mus.cc
index 45dd67e18ef..19596818882 100644
--- a/chromium/ui/aura/mus/window_port_mus.cc
+++ b/chromium/ui/aura/mus/window_port_mus.cc
@@ -4,7 +4,6 @@
#include "ui/aura/mus/window_port_mus.h"
-#include "base/memory/ptr_util.h"
#include "components/viz/client/local_surface_id_provider.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "ui/aura/client/aura_constants.h"
@@ -96,11 +95,19 @@ void WindowPortMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
window_tree_client_->SetHitTestMask(this, rect);
}
-void WindowPortMus::Embed(
- ui::mojom::WindowTreeClientPtr client,
+void WindowPortMus::Embed(ui::mojom::WindowTreeClientPtr client,
+ uint32_t flags,
+ ui::mojom::WindowTree::EmbedCallback callback) {
+ window_tree_client_->Embed(window_, std::move(client), flags,
+ std::move(callback));
+}
+
+void WindowPortMus::EmbedUsingToken(
+ const base::UnguessableToken& token,
uint32_t flags,
- const ui::mojom::WindowTree::EmbedCallback& callback) {
- window_tree_client_->Embed(window_, std::move(client), flags, callback);
+ ui::mojom::WindowTree::EmbedCallback callback) {
+ window_tree_client_->EmbedUsingToken(window_, token, flags,
+ std::move(callback));
}
std::unique_ptr<viz::ClientLayerTreeFrameSink>
@@ -409,6 +416,16 @@ void WindowPortMus::AllocateLocalSurfaceId() {
UpdatePrimarySurfaceId();
}
+bool WindowPortMus::IsLocalSurfaceIdAllocationSuppressed() const {
+ return parent_local_surface_id_allocator_.is_allocation_suppressed();
+}
+
+viz::ScopedSurfaceIdAllocator WindowPortMus::GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) {
+ return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_,
+ std::move(allocation_task));
+}
+
const viz::LocalSurfaceId& WindowPortMus::GetLocalSurfaceId() {
if (base::FeatureList::IsEnabled(features::kMash))
return local_surface_id_;
@@ -647,7 +664,8 @@ void WindowPortMus::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_);
window_->layer()->SetShowPrimarySurface(
surface_info.id(), window_->bounds().size(), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(),
+ false /* stretch_content_to_fill_bounds */);
window_->layer()->SetFallbackSurfaceId(surface_info.id());
}
diff --git a/chromium/ui/aura/mus/window_port_mus.h b/chromium/ui/aura/mus/window_port_mus.h
index 8228ff89d3c..b1b272a4408 100644
--- a/chromium/ui/aura/mus/window_port_mus.h
+++ b/chromium/ui/aura/mus/window_port_mus.h
@@ -93,7 +93,10 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
// details on arguments.
void Embed(ui::mojom::WindowTreeClientPtr client,
uint32_t flags,
- const ui::mojom::WindowTree::EmbedCallback& callback);
+ ui::mojom::WindowTree::EmbedCallback callback);
+ void EmbedUsingToken(const base::UnguessableToken& token,
+ uint32_t flags,
+ ui::mojom::WindowTree::EmbedCallback callback);
std::unique_ptr<viz::ClientLayerTreeFrameSink> RequestLayerTreeFrameSink(
scoped_refptr<viz::ContextProvider> context_provider,
@@ -273,6 +276,9 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
+ bool IsLocalSurfaceIdAllocationSuppressed() const override;
+ viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) override;
const viz::LocalSurfaceId& GetLocalSurfaceId() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
diff --git a/chromium/ui/aura/mus/window_tree_client.cc b/chromium/ui/aura/mus/window_tree_client.cc
index a75ee126a46..4bbe28f100e 100644
--- a/chromium/ui/aura/mus/window_tree_client.cc
+++ b/chromium/ui/aura/mus/window_tree_client.cc
@@ -38,6 +38,8 @@
#include "ui/aura/env_input_state_controller.h"
#include "ui/aura/mus/capture_synchronizer.h"
#include "ui/aura/mus/drag_drop_controller_mus.h"
+#include "ui/aura/mus/embed_root.h"
+#include "ui/aura/mus/embed_root_delegate.h"
#include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/in_flight_change.h"
#include "ui/aura/mus/input_method_mus.h"
@@ -68,6 +70,10 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
+#if defined(USE_OZONE)
+#include "ui/aura/mus/platform_event_source_mus_ozone.h"
+#endif
+
namespace aura {
namespace {
@@ -80,7 +86,7 @@ struct WindowPortPropertyDataMus : public ui::PropertyData {
// message loop starts, or upon destruction.
class EventAckHandler : public base::RunLoop::NestingObserver {
public:
- explicit EventAckHandler(std::unique_ptr<EventResultCallback> ack_callback)
+ explicit EventAckHandler(EventResultCallback ack_callback)
: ack_callback_(std::move(ack_callback)) {
DCHECK(ack_callback_);
base::RunLoop::AddNestingObserverOnCurrentThread(this);
@@ -89,11 +95,22 @@ class EventAckHandler : public base::RunLoop::NestingObserver {
~EventAckHandler() override {
base::RunLoop::RemoveNestingObserverOnCurrentThread(this);
if (ack_callback_) {
- ack_callback_->Run(handled_ ? ui::mojom::EventResult::HANDLED
- : ui::mojom::EventResult::UNHANDLED);
+ NotifyPlatformEventSource();
+ std::move(ack_callback_)
+ .Run(handled_ ? ui::mojom::EventResult::HANDLED
+ : ui::mojom::EventResult::UNHANDLED);
}
}
+#if defined(USE_OZONE)
+ void SetPlatformEventSourceAndEvent(
+ PlatformEventSourceMus* platform_event_source,
+ ui::Event* event) {
+ event_ = event;
+ platform_event_source_ = platform_event_source;
+ }
+#endif
+
void set_handled(bool handled) { handled_ = handled; }
// base::RunLoop::NestingObserver:
@@ -101,14 +118,25 @@ class EventAckHandler : public base::RunLoop::NestingObserver {
// Acknowledge the event immediately if a nested run loop starts.
// Otherwise we appear unresponsive for the life of the nested run loop.
if (ack_callback_) {
- ack_callback_->Run(ui::mojom::EventResult::HANDLED);
- ack_callback_.reset();
+ NotifyPlatformEventSource();
+ std::move(ack_callback_).Run(ui::mojom::EventResult::HANDLED);
}
}
private:
- std::unique_ptr<EventResultCallback> ack_callback_;
+ void NotifyPlatformEventSource() {
+#if defined(USE_OZONE)
+ if (platform_event_source_)
+ platform_event_source_->OnDidProcessEvent(event_);
+#endif
+ }
+
+ EventResultCallback ack_callback_;
bool handled_ = false;
+#if defined(USE_OZONE)
+ ui::Event* event_ = nullptr;
+ PlatformEventSourceMus* platform_event_source_ = nullptr;
+#endif
DISALLOW_COPY_AND_ASSIGN(EventAckHandler);
};
@@ -174,66 +202,108 @@ ui::Id GetServerIdForWindow(Window* window) {
return window ? WindowMus::Get(window)->server_id() : kInvalidServerId;
}
+// The server operates in pixels. Adjust translations for device scale factors.
+gfx::Transform ConvertTransformFromServer(WindowMus* window,
+ const gfx::Transform& transform) {
+ const float scale = window->GetDeviceScaleFactor();
+ if (scale == 1.0f)
+ return transform;
+
+ gfx::Transform dip_transform = transform;
+ dip_transform.matrix().set(0, 3, dip_transform.matrix().get(0, 3) / scale);
+ dip_transform.matrix().set(1, 3, dip_transform.matrix().get(1, 3) / scale);
+ dip_transform.matrix().set(2, 3, dip_transform.matrix().get(2, 3) / scale);
+ return dip_transform;
+}
+
+// See the comment for ConvertTransformFromServer().
+gfx::Transform ConvertTransformToServer(WindowMus* window,
+ const gfx::Transform& transform) {
+ const float scale = window->GetDeviceScaleFactor();
+ if (scale == 1.0f)
+ return transform;
+
+ gfx::Transform pixel_transform = transform;
+ pixel_transform.matrix().set(0, 3, transform.matrix().get(0, 3) * scale);
+ pixel_transform.matrix().set(1, 3, transform.matrix().get(1, 3) * scale);
+ pixel_transform.matrix().set(2, 3, transform.matrix().get(2, 3) * scale);
+ return pixel_transform;
+}
+
} // namespace
-WindowTreeClient::WindowTreeClient(
+// static
+std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForWindowManager(
service_manager::Connector* connector,
WindowTreeClientDelegate* delegate,
WindowManagerDelegate* window_manager_delegate,
- mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request,
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
- bool create_discardable_memory)
- : connector_(connector),
- next_window_id_(1),
- next_change_id_(1),
- delegate_(delegate),
- window_manager_delegate_(window_manager_delegate),
- binding_(this),
- tree_(nullptr),
- in_destructor_(false),
- weak_factory_(this) {
- DCHECK(delegate_);
- // Allow for a null request in tests.
- if (request.is_pending())
- binding_.Bind(std::move(request));
- // Some tests may not create a TransientWindowClient.
- if (client::GetTransientWindowClient())
- client::GetTransientWindowClient()->AddObserver(this);
- if (window_manager_delegate)
- window_manager_delegate->SetWindowManagerClient(this);
- if (connector) { // |connector| can be null in tests.
- if (!io_task_runner) {
- // |io_task_runner| is null in most case. But for the browser process,
- // the |io_task_runner| is the browser's IO thread.
- io_thread_ = std::make_unique<base::Thread>("IOThread");
- base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
- thread_options.priority = base::ThreadPriority::NORMAL;
- CHECK(io_thread_->StartWithOptions(thread_options));
- io_task_runner = io_thread_->task_runner();
- }
+ bool automatically_create_display_roots,
+ bool create_discardable_memory) {
+ std::unique_ptr<WindowTreeClient> wtc(
+ new WindowTreeClient(connector, delegate, window_manager_delegate,
+ nullptr, nullptr, create_discardable_memory));
- if (base::FeatureList::IsEnabled(features::kMash)) {
- gpu_ =
- ui::Gpu::Create(connector, ui::mojom::kServiceName, io_task_runner);
- compositor_context_factory_ =
- std::make_unique<MusContextFactory>(gpu_.get());
- initial_context_factory_ = Env::GetInstance()->context_factory();
- Env::GetInstance()->set_context_factory(
- compositor_context_factory_.get());
- }
+ ui::mojom::WindowManagerWindowTreeFactoryPtr factory;
+ connector->BindInterface(ui::mojom::kServiceName, &factory);
+ ui::mojom::WindowTreePtr window_tree;
+ ui::mojom::WindowTreeClientPtr client;
+ wtc->binding_.Bind(MakeRequest(&client));
+ factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client),
+ automatically_create_display_roots);
+ wtc->SetWindowTree(std::move(window_tree));
+ wtc->CreatePlatformEventSourceIfNecessary();
+ return wtc;
+}
- // WindowServerTest will create more than one WindowTreeClient. We will not
- // create the discardable memory manager for those tests.
- if (create_discardable_memory) {
- discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr;
- connector->BindInterface(ui::mojom::kServiceName, &manager_ptr);
- discardable_shared_memory_manager_ = std::make_unique<
- discardable_memory::ClientDiscardableSharedMemoryManager>(
- std::move(manager_ptr), std::move(io_task_runner));
- base::DiscardableMemoryAllocator::SetInstance(
- discardable_shared_memory_manager_.get());
- }
- }
+// static
+std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForEmbedding(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ ui::mojom::WindowTreeClientRequest request,
+ bool create_discardable_memory) {
+ std::unique_ptr<WindowTreeClient> wtc(
+ new WindowTreeClient(connector, delegate, nullptr, std::move(request),
+ nullptr, create_discardable_memory));
+ return wtc;
+}
+
+// static
+std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForWindowTreeFactory(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ bool create_discardable_memory,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+ std::unique_ptr<WindowTreeClient> wtc(
+ new WindowTreeClient(connector, delegate, nullptr, nullptr, nullptr,
+ create_discardable_memory));
+ ui::mojom::WindowTreeFactoryPtr factory;
+ connector->BindInterface(ui::mojom::kServiceName, &factory);
+ ui::mojom::WindowTreePtr window_tree;
+ ui::mojom::WindowTreeClientPtr client;
+ wtc->binding_.Bind(MakeRequest(&client));
+ factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client));
+ wtc->SetWindowTree(std::move(window_tree));
+ return wtc;
+}
+
+// static
+std::unique_ptr<WindowTreeClient>
+WindowTreeClient::CreateForWindowTreeHostFactory(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ bool create_discardable_memory) {
+ std::unique_ptr<WindowTreeClient> wtc(
+ new WindowTreeClient(connector, delegate, nullptr, nullptr, nullptr,
+ create_discardable_memory));
+ ui::mojom::WindowTreeHostFactoryPtr factory;
+ connector->BindInterface(ui::mojom::kServiceName, &factory);
+
+ ui::mojom::WindowTreeHostPtr window_tree_host;
+ ui::mojom::WindowTreeClientPtr client;
+ wtc->binding_.Bind(MakeRequest(&client));
+ factory->CreateWindowTreeHost(MakeRequest(&window_tree_host),
+ std::move(client));
+ return wtc;
}
WindowTreeClient::~WindowTreeClient() {
@@ -278,46 +348,14 @@ WindowTreeClient::~WindowTreeClient() {
for (auto& pair : windows)
WindowPortForShutdown::Install(pair.second->GetWindow());
+ // EmbedRoots keep a reference to this; so they must all be destroyed before
+ // the destructor completes.
+ DCHECK(embed_roots_.empty());
+
env->WindowTreeClientDestroyed(this);
CHECK(windows_.empty());
}
-void WindowTreeClient::ConnectViaWindowTreeFactory() {
- ui::mojom::WindowTreeFactoryPtr factory;
- connector_->BindInterface(ui::mojom::kServiceName, &factory);
- ui::mojom::WindowTreePtr window_tree;
- ui::mojom::WindowTreeClientPtr client;
- binding_.Bind(MakeRequest(&client));
- factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client));
- SetWindowTree(std::move(window_tree));
-}
-
-void WindowTreeClient::ConnectAsWindowManager(
- bool automatically_create_display_roots) {
- DCHECK(window_manager_delegate_);
-
- ui::mojom::WindowManagerWindowTreeFactoryPtr factory;
- connector_->BindInterface(ui::mojom::kServiceName, &factory);
- ui::mojom::WindowTreePtr window_tree;
- ui::mojom::WindowTreeClientPtr client;
- binding_.Bind(MakeRequest(&client));
- factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client),
- automatically_create_display_roots);
- SetWindowTree(std::move(window_tree));
-}
-
-void WindowTreeClient::ConnectViaWindowTreeHostFactory() {
- ui::mojom::WindowTreeHostFactoryPtr factory;
- connector_->BindInterface(ui::mojom::kServiceName, &factory);
-
- ui::mojom::WindowTreeHostPtr window_tree_host;
- ui::mojom::WindowTreeClientPtr client;
- binding_.Bind(MakeRequest(&client));
- factory->CreateWindowTreeHost(MakeRequest(&window_tree_host),
- std::move(client));
- WaitForInitialDisplays();
-}
-
void WindowTreeClient::SetCanFocus(Window* window, bool can_focus) {
DCHECK(tree_);
DCHECK(window);
@@ -360,11 +398,10 @@ void WindowTreeClient::SetHitTestMask(
tree_->SetHitTestMask(window->server_id(), out_rect);
}
-void WindowTreeClient::Embed(
- Window* window,
- ui::mojom::WindowTreeClientPtr client,
- uint32_t flags,
- const ui::mojom::WindowTree::EmbedCallback& callback) {
+void WindowTreeClient::Embed(Window* window,
+ ui::mojom::WindowTreeClientPtr client,
+ uint32_t flags,
+ ui::mojom::WindowTree::EmbedCallback callback) {
DCHECK(tree_);
// Window::Init() must be called before Embed() (otherwise the server hasn't
// been told about the window).
@@ -373,19 +410,39 @@ void WindowTreeClient::Embed(
// The window server removes all children before embedding. In other words,
// it's generally an error to Embed() with existing children. So, fail
// early.
- callback.Run(false);
+ std::move(callback).Run(false);
return;
}
tree_->Embed(WindowMus::Get(window)->server_id(), std::move(client), flags,
- callback);
+ std::move(callback));
}
void WindowTreeClient::ScheduleEmbed(
ui::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) {
- tree_->ScheduleEmbed(std::move(client),
- base::AdaptCallbackForRepeating(std::move(callback)));
+ tree_->ScheduleEmbed(std::move(client), std::move(callback));
+}
+
+void WindowTreeClient::EmbedUsingToken(
+ Window* window,
+ const base::UnguessableToken& token,
+ uint32_t flags,
+ ui::mojom::WindowTree::EmbedCallback callback) {
+ DCHECK(tree_);
+ // Window::Init() must be called before Embed() (otherwise the server hasn't
+ // been told about the window).
+ DCHECK(window->layer());
+ if (!window->children().empty()) {
+ // The window server removes all children before embedding. In other words,
+ // it's generally an error to Embed() with existing children. So, fail
+ // early.
+ std::move(callback).Run(false);
+ return;
+ }
+
+ tree_->EmbedUsingToken(WindowMus::Get(window)->server_id(), token, flags,
+ std::move(callback));
}
void WindowTreeClient::AttachCompositorFrameSink(
@@ -397,6 +454,81 @@ void WindowTreeClient::AttachCompositorFrameSink(
std::move(client));
}
+std::unique_ptr<EmbedRoot> WindowTreeClient::CreateEmbedRoot(
+ EmbedRootDelegate* delegate) {
+ std::unique_ptr<EmbedRoot> embed_root =
+ base::WrapUnique(new EmbedRoot(this, delegate, next_window_id_++));
+ embed_roots_.insert(embed_root.get());
+ return embed_root;
+}
+
+WindowTreeClient::WindowTreeClient(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ WindowManagerDelegate* window_manager_delegate,
+ mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ bool create_discardable_memory)
+ : connector_(connector),
+ next_window_id_(1),
+ next_change_id_(1),
+ delegate_(delegate),
+ window_manager_delegate_(window_manager_delegate),
+ binding_(this),
+ tree_(nullptr),
+ in_destructor_(false),
+ weak_factory_(this) {
+ DCHECK(delegate_);
+ // Allow for a null request in tests.
+ if (request.is_pending())
+ binding_.Bind(std::move(request));
+ // Some tests may not create a TransientWindowClient.
+ if (client::GetTransientWindowClient())
+ client::GetTransientWindowClient()->AddObserver(this);
+ if (window_manager_delegate)
+ window_manager_delegate->SetWindowManagerClient(this);
+ if (connector) { // |connector| can be null in tests.
+ if (!io_task_runner) {
+ // |io_task_runner| is null in most case. But for the browser process,
+ // the |io_task_runner| is the browser's IO thread.
+ io_thread_ = std::make_unique<base::Thread>("IOThread");
+ base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
+ thread_options.priority = base::ThreadPriority::NORMAL;
+ CHECK(io_thread_->StartWithOptions(thread_options));
+ io_task_runner = io_thread_->task_runner();
+ }
+
+ if (base::FeatureList::IsEnabled(features::kMash)) {
+ gpu_ =
+ ui::Gpu::Create(connector, ui::mojom::kServiceName, io_task_runner);
+ compositor_context_factory_ =
+ std::make_unique<MusContextFactory>(gpu_.get());
+ initial_context_factory_ = Env::GetInstance()->context_factory();
+ Env::GetInstance()->set_context_factory(
+ compositor_context_factory_.get());
+ }
+
+ // WindowServerTest will create more than one WindowTreeClient. We will not
+ // create the discardable memory manager for those tests.
+ if (create_discardable_memory) {
+ discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr;
+ connector->BindInterface(ui::mojom::kServiceName, &manager_ptr);
+ discardable_shared_memory_manager_ = std::make_unique<
+ discardable_memory::ClientDiscardableSharedMemoryManager>(
+ std::move(manager_ptr), std::move(io_task_runner));
+ base::DiscardableMemoryAllocator::SetInstance(
+ discardable_shared_memory_manager_.get());
+ }
+ }
+}
+
+void WindowTreeClient::CreatePlatformEventSourceIfNecessary() {
+#if defined(USE_OZONE)
+ if (!ui::PlatformEventSource::GetInstance())
+ platform_event_source_ = std::make_unique<PlatformEventSourceMus>();
+#endif
+}
+
void WindowTreeClient::RegisterWindowMus(WindowMus* window) {
DCHECK(windows_.find(window->server_id()) == windows_.end());
windows_[window->server_id()] = window;
@@ -649,10 +781,10 @@ void WindowTreeClient::SetWindowTree(ui::mojom::WindowTreePtr window_tree_ptr) {
WindowTreeConnectionEstablished(tree_ptr_.get());
tree_ptr_->GetCursorLocationMemory(
- base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&WindowTreeClient::OnReceivedCursorLocationMemory,
+ weak_factory_.GetWeakPtr()));
- tree_ptr_.set_connection_error_handler(base::Bind(
+ tree_ptr_.set_connection_error_handler(base::BindOnce(
&WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr()));
if (window_manager_delegate_) {
@@ -720,6 +852,18 @@ void WindowTreeClient::OnEmbedImpl(
delegate_->OnEmbed(std::move(window_tree_host));
}
+EmbedRoot* WindowTreeClient::GetEmbedRootWithRootWindow(aura::Window* window) {
+ for (EmbedRoot* embed_root : embed_roots_) {
+ if (embed_root->window() == window)
+ return embed_root;
+ }
+ return nullptr;
+}
+
+void WindowTreeClient::OnEmbedRootDestroyed(EmbedRoot* embed_root) {
+ embed_roots_.erase(embed_root);
+}
+
WindowTreeHostMus* WindowTreeClient::WmNewDisplayAddedImpl(
const display::Display& display,
ui::mojom::WindowDataPtr root_data,
@@ -741,11 +885,10 @@ WindowTreeHostMus* WindowTreeClient::WmNewDisplayAddedImpl(
return window_tree_host_ptr;
}
-std::unique_ptr<EventResultCallback>
-WindowTreeClient::CreateEventResultCallback(int32_t event_id) {
- return std::make_unique<EventResultCallback>(
- base::Bind(&ui::mojom::WindowTree::OnWindowInputEventAck,
- base::Unretained(tree_), event_id));
+EventResultCallback WindowTreeClient::CreateEventResultCallback(
+ int32_t event_id) {
+ return base::BindOnce(&ui::mojom::WindowTree::OnWindowInputEventAck,
+ base::Unretained(tree_), event_id);
}
void WindowTreeClient::OnReceivedCursorLocationMemory(
@@ -777,7 +920,7 @@ void WindowTreeClient::SetWindowBoundsFromServer(
void WindowTreeClient::SetWindowTransformFromServer(
WindowMus* window,
const gfx::Transform& transform) {
- window->SetTransformFromServer(transform);
+ window->SetTransformFromServer(ConvertTransformFromServer(window, transform));
}
void WindowTreeClient::SetWindowVisibleFromServer(WindowMus* window,
@@ -882,7 +1025,7 @@ void WindowTreeClient::OnWindowMusCreated(WindowMus* window) {
base::FeatureList::IsEnabled(features::kMash)
? display_init_params->mirrors
: std::vector<display::Display>(),
- base::Bind(&OnAckMustSucceed, FROM_HERE));
+ base::BindOnce(&OnAckMustSucceed, FROM_HERE));
}
}
}
@@ -950,7 +1093,7 @@ void WindowTreeClient::OnWindowMusBoundsChanged(WindowMus* window,
return;
}
- float device_scale_factor = window->GetDeviceScaleFactor();
+ const float device_scale_factor = window->GetDeviceScaleFactor();
ScheduleInFlightBoundsChange(
window, gfx::ConvertRectToPixel(device_scale_factor, old_bounds),
gfx::ConvertRectToPixel(device_scale_factor, new_bounds));
@@ -962,7 +1105,8 @@ void WindowTreeClient::OnWindowMusTransformChanged(
const gfx::Transform& new_transform) {
const uint32_t change_id = ScheduleInFlightChange(
std::make_unique<InFlightTransformChange>(this, window, old_transform));
- tree_->SetWindowTransform(change_id, window->server_id(), new_transform);
+ tree_->SetWindowTransform(change_id, window->server_id(),
+ ConvertTransformToServer(window, new_transform));
}
void WindowTreeClient::OnWindowMusAddChild(WindowMus* parent,
@@ -1175,6 +1319,20 @@ void WindowTreeClient::OnEmbed(
focused_window_id, drawn, local_surface_id);
}
+void WindowTreeClient::OnEmbedFromToken(
+ const base::UnguessableToken& token,
+ ui::mojom::WindowDataPtr root,
+ int64_t display_id,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
+ for (EmbedRoot* embed_root : embed_roots_) {
+ if (embed_root->token() == token) {
+ embed_root->OnEmbed(CreateWindowTreeHost(WindowMusType::EMBED, *root,
+ display_id, local_surface_id));
+ break;
+ }
+ }
+}
+
void WindowTreeClient::OnEmbeddedAppDisconnected(ui::Id window_id) {
WindowMus* window = GetWindowByServerId(window_id);
if (window)
@@ -1186,6 +1344,13 @@ void WindowTreeClient::OnUnembed(ui::Id window_id) {
if (!window)
return;
+ EmbedRoot* embed_root = GetEmbedRootWithRootWindow(window->GetWindow());
+ if (embed_root) {
+ embed_root->OnUnembed();
+ if (!GetWindowByServerId(window_id))
+ return; // EmbedRoot was deleted, resulting in deleting window.
+ }
+
delegate_->OnUnembed(window->GetWindow());
delete window;
}
@@ -1404,11 +1569,15 @@ void WindowTreeClient::OnWindowDeleted(ui::Id window_id) {
if (roots_.count(window)) {
// Roots are associated with WindowTreeHosts. The WindowTreeHost owns the
// root, so we have to delete the WindowTreeHost to indirectly delete the
- // Window. Additionally clients may want to do extra processing before the
- // delete, so call to the delegate to handle it. Let the window know it is
- // going to be deleted so we don't callback to the server.
+ // Window. Clients may want to do extra processing before the delete,
+ // notify the appropriate delegate to handle the deletion. Let the window
+ // know it is going to be deleted so we don't callback to the server.
window->PrepareForDestroy();
- delegate_->OnEmbedRootDestroyed(GetWindowTreeHostMus(window));
+ EmbedRoot* embed_root = GetEmbedRootWithRootWindow(window->GetWindow());
+ if (embed_root)
+ embed_root->OnUnembed();
+ else
+ delegate_->OnEmbedRootDestroyed(GetWindowTreeHostMus(window));
} else {
window->DestroyFromServer();
}
@@ -1516,7 +1685,6 @@ void WindowTreeClient::OnWindowInputEvent(
}
}
- EventAckHandler ack_handler(CreateEventResultCallback(event_id));
// TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or
// ui::TouchEvent once we have proper support for pointer events.
std::unique_ptr<ui::Event> mapped_event = MapEvent(*event.get());
@@ -1532,7 +1700,7 @@ void WindowTreeClient::OnWindowInputEvent(
if (mapped_event->type() == ui::ET_MOUSE_MOVED ||
mapped_event->type() == ui::ET_MOUSE_DRAGGED) {
mapped_event_with_native = std::make_unique<ui::MouseEvent>(
- static_cast<const base::NativeEvent&>(mapped_event.get()));
+ static_cast<const ui::PlatformEvent&>(mapped_event.get()));
// MouseEvent(NativeEvent) sets the root_location to location.
mapped_event_with_native->set_root_location_f(
event_location_in_screen_pixel_layout);
@@ -1543,6 +1711,13 @@ void WindowTreeClient::OnWindowInputEvent(
event_to_dispatch = mapped_event_with_native.get();
}
#endif
+ // |ack_handler| may use |event_to_dispatch| from its destructor, so it needs
+ // to be destroyed after |event_to_dispatch| is destroyed.
+ EventAckHandler ack_handler(CreateEventResultCallback(event_id));
+#if defined(USE_OZONE)
+ ack_handler.SetPlatformEventSourceAndEvent(platform_event_source_.get(),
+ event_to_dispatch);
+#endif
WindowMus* display_root_window = GetWindowByServerId(display_root_window_id);
if (display_root_window && event->IsLocatedEvent() &&
@@ -1562,6 +1737,11 @@ void WindowTreeClient::OnWindowInputEvent(
// focused window, which may have changed by the time we process the event.
ui::Event::DispatcherApi(event_to_dispatch).set_target(window->GetWindow());
}
+#if defined(USE_OZONE)
+ if (platform_event_source_)
+ platform_event_source_->OnWillProcessEvent(event_to_dispatch);
+#endif
+
GetWindowTreeHostMus(window)->SendEventToSink(event_to_dispatch);
ack_handler.set_handled(event_to_dispatch->handled());
@@ -1630,8 +1810,8 @@ void WindowTreeClient::OnDragEnter(ui::Id window_id,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnDragEnterCallback& callback) {
- callback.Run(drag_drop_controller_->OnDragEnter(
+ OnDragEnterCallback callback) {
+ std::move(callback).Run(drag_drop_controller_->OnDragEnter(
GetWindowByServerId(window_id), key_state, position, effect_bitmask));
}
@@ -1639,8 +1819,8 @@ void WindowTreeClient::OnDragOver(ui::Id window_id,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnDragOverCallback& callback) {
- callback.Run(drag_drop_controller_->OnDragOver(
+ OnDragOverCallback callback) {
+ std::move(callback).Run(drag_drop_controller_->OnDragOver(
GetWindowByServerId(window_id), key_state, position, effect_bitmask));
}
@@ -1656,8 +1836,8 @@ void WindowTreeClient::OnCompleteDrop(ui::Id window_id,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnCompleteDropCallback& callback) {
- callback.Run(drag_drop_controller_->OnCompleteDrop(
+ OnCompleteDropCallback callback) {
+ std::move(callback).Run(drag_drop_controller_->OnCompleteDrop(
GetWindowByServerId(window_id), key_state, position, effect_bitmask));
}
@@ -1716,7 +1896,7 @@ void WindowTreeClient::SetBlockingContainers(
}
window_manager_client_->SetBlockingContainers(
std::move(transport_all_blocking_containers),
- base::Bind(&OnAckMustSucceed, FROM_HERE));
+ base::BindOnce(&OnAckMustSucceed, FROM_HERE));
}
void WindowTreeClient::GetWindowManager(
@@ -1909,16 +2089,11 @@ void WindowTreeClient::WmBuildDragImage(const gfx::Point& screen_location,
drag_image_offset, source);
}
-void WindowTreeClient::WmMoveDragImage(
- const gfx::Point& screen_location,
- const WmMoveDragImageCallback& callback) {
- if (!window_manager_delegate_) {
- callback.Run();
- return;
- }
-
- window_manager_delegate_->OnWmMoveDragImage(screen_location);
- callback.Run();
+void WindowTreeClient::WmMoveDragImage(const gfx::Point& screen_location,
+ WmMoveDragImageCallback callback) {
+ if (window_manager_delegate_)
+ window_manager_delegate_->OnWmMoveDragImage(screen_location);
+ std::move(callback).Run();
}
void WindowTreeClient::WmDestroyDragImage() {
@@ -2165,8 +2340,8 @@ void WindowTreeClient::InjectEvent(const ui::Event& event, int64_t display_id) {
// Check event_injector_ so we don't crash if access to the interface was
// refused.
if (event_injector_) {
- event_injector_->DispatchEvent(display_id, ui::Event::Clone(event),
- base::DoNothing());
+ event_injector_->InjectEvent(display_id, ui::Event::Clone(event),
+ base::DoNothing());
}
}
@@ -2197,7 +2372,8 @@ void WindowTreeClient::SetDisplayConfiguration(
: display::kInvalidDisplayId;
window_manager_client_->SetDisplayConfiguration(
displays, std::move(viewport_metrics), primary_display_id,
- internal_display_id, mirrors, base::Bind(&OnAckMustSucceed, FROM_HERE));
+ internal_display_id, mirrors,
+ base::BindOnce(&OnAckMustSucceed, FROM_HERE));
}
}
@@ -2216,7 +2392,7 @@ void WindowTreeClient::AddDisplayReusingWindowTreeHost(
window_manager_client_->SetDisplayRoot(
display, std::move(viewport_metrics), is_primary_display,
display_root_window->server_id(), mirrors,
- base::Bind(&OnAckMustSucceed, FROM_HERE));
+ base::BindOnce(&OnAckMustSucceed, FROM_HERE));
window_tree_host->compositor()->SetLocalSurfaceId(
display_root_window->GetOrAllocateLocalSurfaceId(
window_tree_host->GetBoundsInPixels().size()));
@@ -2240,7 +2416,7 @@ void WindowTreeClient::SwapDisplayRoots(WindowTreeHostMus* window_tree_host1,
if (window_manager_client_) {
window_manager_client_->SwapDisplayRoots(
- display_id1, display_id2, base::Bind(&OnAckMustSucceed, FROM_HERE));
+ display_id1, display_id2, base::BindOnce(&OnAckMustSucceed, FROM_HERE));
}
}
diff --git a/chromium/ui/aura/mus/window_tree_client.h b/chromium/ui/aura/mus/window_tree_client.h
index 1a887b9a322..8cd0e54f3c7 100644
--- a/chromium/ui/aura/mus/window_tree_client.h
+++ b/chromium/ui/aura/mus/window_tree_client.h
@@ -15,6 +15,7 @@
#include "base/atomicops.h"
#include "base/compiler_specific.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
@@ -23,7 +24,7 @@
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/ui/public/interfaces/remote_event_dispatcher.mojom.h"
+#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/transient_window_client_observer.h"
@@ -64,12 +65,15 @@ struct PropertyData;
namespace aura {
class CaptureSynchronizer;
class DragDropControllerMus;
+class EmbedRoot;
+class EmbedRootDelegate;
class FocusSynchronizer;
class InFlightBoundsChange;
class InFlightChange;
class InFlightFocusChange;
class InFlightPropertyChange;
class InFlightVisibleChange;
+class PlatformEventSourceMus;
class MusContextFactory;
class WindowMus;
class WindowPortMus;
@@ -79,13 +83,15 @@ class WindowTreeClientObserver;
class WindowTreeClientTestObserver;
class WindowTreeHostMus;
-using EventResultCallback = base::Callback<void(ui::mojom::EventResult)>;
+using EventResultCallback = base::OnceCallback<void(ui::mojom::EventResult)>;
-// Manages the connection with mus.
+// Used to enable Aura to act as the client-library for the Window Service.
//
-// WindowTreeClient is owned by the creator. Generally when the delegate gets
-// one of OnEmbedRootDestroyed() or OnLostConnection() it should delete the
-// WindowTreeClient.
+// WindowTreeClient is created in a handful of distinct ways. See the various
+// Create functions for details.
+//
+// Generally when the delegate gets one of OnEmbedRootDestroyed() or
+// OnLostConnection() it should delete the WindowTreeClient.
//
// When WindowTreeClient is deleted all windows are deleted (and observers
// notified).
@@ -99,31 +105,38 @@ class AURA_EXPORT WindowTreeClient
public WindowTreeHostMusDelegate,
public client::TransientWindowClientObserver {
public:
- // |create_discardable_memory| If it is true, WindowTreeClient will setup the
- // dicardable shared memory manager for this process. In some test, more than
- // one WindowTreeClient will be created, so we need pass false to avoid
- // setup the discardable shared memory manager more than once.
- WindowTreeClient(
+ // Creates a WindowTreeClient to act as the window manager. See mojom for
+ // details on |automatically_create_display_roots|.
+ // TODO(sky): move |create_discardable_memory| out of this class.
+ static std::unique_ptr<WindowTreeClient> CreateForWindowManager(
service_manager::Connector* connector,
WindowTreeClientDelegate* delegate,
- WindowManagerDelegate* window_manager_delegate = nullptr,
- ui::mojom::WindowTreeClientRequest request = nullptr,
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr,
+ WindowManagerDelegate* window_manager_delegate,
+ bool automatically_create_display_roots = true,
bool create_discardable_memory = true);
- ~WindowTreeClient() override;
- // Establishes the connection by way of the WindowTreeFactory.
- void ConnectViaWindowTreeFactory();
+ // Creates a WindowTreeClient for use in embedding.
+ static std::unique_ptr<WindowTreeClient> CreateForEmbedding(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ ui::mojom::WindowTreeClientRequest request,
+ bool create_discardable_memory = true);
- // Establishes the connection by way of WindowManagerWindowTreeFactory.
- // See mojom for details on |automatically_create_display_roots|.
- void ConnectAsWindowManager(bool automatically_create_display_roots = true);
+ // Creates a WindowTreeClient useful for creating top-level windows.
+ static std::unique_ptr<WindowTreeClient> CreateForWindowTreeFactory(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ bool create_discardable_memory = true,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr);
+
+ // Creates a WindowTreeClient such that the Window Service creates a single
+ // WindowTreeHost. This is useful for testing and examples.
+ static std::unique_ptr<WindowTreeClient> CreateForWindowTreeHostFactory(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ bool create_discardable_memory = true);
- // Connects to mus such that a single WindowTreeHost is created. This blocks
- // until the WindowTreeHost is obtained and calls
- // WindowTreeClientDelegate::OnEmbed() with the WindowTreeHost. This entry
- // point is mostly useful for testing and examples.
- void ConnectViaWindowTreeHostFactory();
+ ~WindowTreeClient() override;
void DisableDragDropClient() { install_drag_drop_client_ = false; }
@@ -156,7 +169,11 @@ class AURA_EXPORT WindowTreeClient
void Embed(Window* window,
ui::mojom::WindowTreeClientPtr client,
uint32_t flags,
- const ui::mojom::WindowTree::EmbedCallback& callback);
+ ui::mojom::WindowTree::EmbedCallback callback);
+ void EmbedUsingToken(Window* window,
+ const base::UnguessableToken& token,
+ uint32_t flags,
+ ui::mojom::WindowTree::EmbedCallback callback);
// Schedules an embed of a client. See
// mojom::WindowTreeClient::ScheduleEmbed() for details.
@@ -164,6 +181,9 @@ class AURA_EXPORT WindowTreeClient
ui::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback);
+ // Creates a new EmbedRoot. See EmbedRoot for details.
+ std::unique_ptr<EmbedRoot> CreateEmbedRoot(EmbedRootDelegate* delegate);
+
void AttachCompositorFrameSink(
ui::Id window_id,
viz::mojom::CompositorFrameSinkRequest compositor_frame_sink,
@@ -194,6 +214,7 @@ class AURA_EXPORT WindowTreeClient
void RemoveTestObserver(WindowTreeClientTestObserver* observer);
private:
+ friend class EmbedRoot;
friend class InFlightBoundsChange;
friend class InFlightFocusChange;
friend class InFlightPropertyChange;
@@ -212,6 +233,21 @@ class AURA_EXPORT WindowTreeClient
// TODO(sky): this assumes change_ids never wrap, which is a bad assumption.
using InFlightMap = std::map<uint32_t, std::unique_ptr<InFlightChange>>;
+ // |create_discardable_memory| specifies whether WindowTreeClient will setup
+ // the dicardable shared memory manager for this process. In some tests, more
+ // than one WindowTreeClient will be created, so we need to pass false to
+ // avoid setting up the discardable shared memory manager more than once.
+ WindowTreeClient(
+ service_manager::Connector* connector,
+ WindowTreeClientDelegate* delegate,
+ WindowManagerDelegate* window_manager_delegate = nullptr,
+ ui::mojom::WindowTreeClientRequest request = nullptr,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr,
+ bool create_discardable_memory = true);
+
+ // Creates a PlatformEventSourceMus if not created yet.
+ void CreatePlatformEventSourceIfNecessary();
+
void RegisterWindowMus(WindowMus* window);
WindowMus* GetWindowByServerId(ui::Id id);
@@ -300,6 +336,12 @@ class AURA_EXPORT WindowTreeClient
bool drawn,
const base::Optional<viz::LocalSurfaceId>& local_surface_id);
+ // Returns the EmbedRoot whose root is |window|, or null if there isn't one.
+ EmbedRoot* GetEmbedRootWithRootWindow(aura::Window* window);
+
+ // Called from EmbedRoot's destructor.
+ void OnEmbedRootDestroyed(EmbedRoot* embed_root);
+
// Called by WmNewDisplayAdded().
WindowTreeHostMus* WmNewDisplayAddedImpl(
const display::Display& display,
@@ -307,8 +349,7 @@ class AURA_EXPORT WindowTreeClient
bool parent_drawn,
const base::Optional<viz::LocalSurfaceId>& local_surface_id);
- std::unique_ptr<EventResultCallback> CreateEventResultCallback(
- int32_t event_id);
+ EventResultCallback CreateEventResultCallback(int32_t event_id);
void OnReceivedCursorLocationMemory(mojo::ScopedSharedBufferHandle handle);
@@ -364,6 +405,11 @@ class AURA_EXPORT WindowTreeClient
ui::Id focused_window_id,
bool drawn,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
+ void OnEmbedFromToken(
+ const base::UnguessableToken& token,
+ ui::mojom::WindowDataPtr root,
+ int64_t display_id,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
void OnEmbeddedAppDisconnected(ui::Id window_id) override;
void OnUnembed(ui::Id window_id) override;
void OnCaptureChanged(ui::Id new_capture_window_id,
@@ -432,18 +478,18 @@ class AURA_EXPORT WindowTreeClient
uint32_t event_flags,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnDragEnterCallback& callback) override;
+ OnDragEnterCallback callback) override;
void OnDragOver(ui::Id window_id,
uint32_t event_flags,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnDragOverCallback& callback) override;
+ OnDragOverCallback callback) override;
void OnDragLeave(ui::Id window_id) override;
void OnCompleteDrop(ui::Id window_id,
uint32_t event_flags,
const gfx::Point& position,
uint32_t effect_bitmask,
- const OnCompleteDropCallback& callback) override;
+ OnCompleteDropCallback callback) override;
void OnPerformDragDropCompleted(uint32_t change_id,
bool success,
uint32_t action_taken) override;
@@ -489,7 +535,7 @@ class AURA_EXPORT WindowTreeClient
const gfx::Vector2d& drag_image_offset,
ui::mojom::PointerKind source) override;
void WmMoveDragImage(const gfx::Point& screen_location,
- const WmMoveDragImageCallback& callback) override;
+ WmMoveDragImageCallback callback) override;
void WmDestroyDragImage() override;
void WmPerformMoveLoop(uint32_t change_id,
ui::Id window_id,
@@ -616,6 +662,8 @@ class AURA_EXPORT WindowTreeClient
std::set<WindowMus*> roots_;
+ base::flat_set<EmbedRoot*> embed_roots_;
+
IdToWindowMap windows_;
std::map<ui::ClientSpecificId, std::set<Window*>> embedded_windows_;
@@ -649,7 +697,7 @@ class AURA_EXPORT WindowTreeClient
// WindowManagerClient set this, but not |window_manager_internal_client_|.
ui::mojom::WindowManagerClient* window_manager_client_ = nullptr;
- ui::mojom::RemoteEventDispatcherPtr event_injector_;
+ ui::mojom::EventInjectorPtr event_injector_;
bool has_pointer_watcher_ = false;
@@ -692,6 +740,10 @@ class AURA_EXPORT WindowTreeClient
// removed.
bool install_drag_drop_client_ = true;
+#if defined(USE_OZONE)
+ std::unique_ptr<PlatformEventSourceMus> platform_event_source_;
+#endif
+
base::WeakPtrFactory<WindowTreeClient> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeClient);
diff --git a/chromium/ui/aura/mus/window_tree_client_unittest.cc b/chromium/ui/aura/mus/window_tree_client_unittest.cc
index 1ed6c0c3428..1059364d435 100644
--- a/chromium/ui/aura/mus/window_tree_client_unittest.cc
+++ b/chromium/ui/aura/mus/window_tree_client_unittest.cc
@@ -27,6 +27,8 @@
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/mus/capture_synchronizer.h"
#include "ui/aura/mus/client_surface_embedder.h"
+#include "ui/aura/mus/embed_root.h"
+#include "ui/aura/mus/embed_root_delegate.h"
#include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/property_converter.h"
#include "ui/aura/mus/window_mus.h"
@@ -36,6 +38,7 @@
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/test/aura_mus_test_base.h"
+#include "ui/aura/test/aura_test_suite.h"
#include "ui/aura/test/mus/test_window_tree.h"
#include "ui/aura/test/mus/window_tree_client_private.h"
#include "ui/aura/test/test_window_delegate.h"
@@ -53,6 +56,8 @@
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
+#include "ui/events/platform/platform_event_observer.h"
+#include "ui/events/platform/platform_event_source.h"
#include "ui/events/test/test_event_handler.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/rect.h"
@@ -2894,7 +2899,7 @@ TEST_F(WindowTreeClientDestructionTest, WindowsFromOtherConnectionsDeleted) {
EXPECT_TRUE(window_tracker.windows().empty());
}
-TEST_F(WindowTreeClientWmTest, ObservedPointerEvents) {
+TEST_F(WindowTreeClientWmTestHighDPI, ObservedPointerEvents) {
const gfx::Rect bounds(1, 2, 101, 102);
std::unique_ptr<DisplayInitParams> display_params =
std::make_unique<DisplayInitParams>();
@@ -2966,4 +2971,109 @@ TEST_F(WindowTreeClientWmTest, ObservedPointerEvents) {
last_event->root_location());
}
+class TestEmbedRootDelegate : public EmbedRootDelegate {
+ public:
+ TestEmbedRootDelegate() = default;
+ ~TestEmbedRootDelegate() override = default;
+
+ // EmbedRootDelegate:
+ void OnEmbedTokenAvailable(const base::UnguessableToken& token) override {}
+ void OnEmbed(Window* window) override {}
+ void OnUnembed() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestEmbedRootDelegate);
+};
+
+// Verifies we don't crash when focus changes to a window in an EmbedRoot.
+TEST_F(WindowTreeClientClientTest, ChangeFocusInEmbedRootWindow) {
+ TestEmbedRootDelegate embed_root_delegate;
+ std::unique_ptr<EmbedRoot> embed_root =
+ window_tree_client_impl()->CreateEmbedRoot(&embed_root_delegate);
+ WindowTreeClientPrivate(window_tree_client_impl())
+ .CallOnEmbedFromToken(embed_root.get());
+ ASSERT_TRUE(embed_root->window());
+ window_tree_client()->OnWindowFocused(server_id(embed_root->window()));
+}
+
+#if defined(USE_OZONE)
+
+class TestPlatformEventObserver : public ui::PlatformEventObserver {
+ public:
+ TestPlatformEventObserver() = default;
+ ~TestPlatformEventObserver() override = default;
+
+ int will_process_count() const { return will_process_count_; }
+ int did_process_count() const { return did_process_count_; }
+ ui::EventType will_process_type() const { return will_process_type_; }
+ ui::EventType did_process_type() const { return did_process_type_; }
+
+ // PlatformEventObserver:
+ void WillProcessEvent(const ui::PlatformEvent& event) override {
+ will_process_count_++;
+ will_process_type_ = static_cast<const ui::Event*>(event)->type();
+ }
+ void DidProcessEvent(const ui::PlatformEvent& event) override {
+ did_process_count_++;
+ did_process_type_ = static_cast<const ui::Event*>(event)->type();
+ }
+
+ private:
+ int will_process_count_ = 0;
+ int did_process_count_ = 0;
+ ui::EventType will_process_type_ = ui::ET_UNKNOWN;
+ ui::EventType did_process_type_ = ui::ET_UNKNOWN;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventObserver);
+};
+
+// Base class that installs a new version of Env configured for Mus in SetUp()
+// (and installs a new version of Env configured for Local during TearDown()).
+// This is necessary as when Env is created with a Model of Local it installs
+// a PlatformEventSource, not the one that WindowTreeClient installs.
+class WindowTreeClientWmOzoneTest : public test::AuraMusWmTestBase {
+ public:
+ WindowTreeClientWmOzoneTest() = default;
+ ~WindowTreeClientWmOzoneTest() override = default;
+
+ // test::AuraMusWmTestBase:
+ void SetUp() override {
+ env_reinstaller_ = std::make_unique<test::EnvReinstaller>();
+ env_ = Env::CreateInstance(Env::Mode::MUS);
+ AuraMusWmTestBase::SetUp();
+ }
+
+ void TearDown() override {
+ AuraMusWmTestBase::TearDown();
+ env_.reset();
+ env_reinstaller_.reset();
+ }
+
+ private:
+ std::unique_ptr<test::EnvReinstaller> env_reinstaller_;
+ std::unique_ptr<Env> env_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeClientWmOzoneTest);
+};
+
+// Used to verify PlatformEventSource is correctly wired up in ozone.
+TEST_F(WindowTreeClientWmOzoneTest, PlatformEventSourceInstalled) {
+ ASSERT_TRUE(ui::PlatformEventSource::GetInstance());
+ TestPlatformEventObserver test_observer;
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(
+ &test_observer);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_NONE, 0);
+ window_tree_client()->OnWindowInputEvent(1, server_id(root_window()), 0,
+ ui::Id(), gfx::PointF(),
+ ui::Event::Clone(event), 0);
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(
+ &test_observer);
+ EXPECT_EQ(1, test_observer.will_process_count());
+ EXPECT_EQ(1, test_observer.did_process_count());
+ EXPECT_EQ(ui::ET_MOUSE_MOVED, test_observer.will_process_type());
+ EXPECT_EQ(ui::ET_MOUSE_MOVED, test_observer.did_process_type());
+}
+#endif
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_tree_host_mus.cc b/chromium/ui/aura/mus/window_tree_host_mus.cc
index 3acab45d4e2..639f26292a8 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus.cc
+++ b/chromium/ui/aura/mus/window_tree_host_mus.cc
@@ -4,7 +4,6 @@
#include "ui/aura/mus/window_tree_host_mus.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/input_method_mus.h"
#include "ui/aura/mus/window_port_mus.h"
@@ -87,6 +86,8 @@ WindowTreeHostMus::WindowTreeHostMus(WindowTreeHostMusInitParams init_params)
this, use_default_accelerated_widget, bounds_in_pixels));
if (!init_params.use_classic_ime) {
+ // NOTE: This creates one InputMethodMus per display, despite the
+ // call to SetSharedInputMethod() below.
input_method_ = std::make_unique<InputMethodMus>(this, window());
input_method_->Init(init_params.window_tree_client->connector());
SetSharedInputMethod(input_method_.get());
diff --git a/chromium/ui/aura/mus/window_tree_host_mus_unittest.cc b/chromium/ui/aura/mus/window_tree_host_mus_unittest.cc
index 3d7714e6f7f..39a7302ed1d 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus_unittest.cc
+++ b/chromium/ui/aura/mus/window_tree_host_mus_unittest.cc
@@ -4,7 +4,6 @@
#include "ui/aura/mus/window_tree_host_mus.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/test/aura_mus_test_base.h"
diff --git a/chromium/ui/aura/scoped_keyboard_hook.cc b/chromium/ui/aura/scoped_keyboard_hook.cc
index 96d9d778439..68348c16f75 100644
--- a/chromium/ui/aura/scoped_keyboard_hook.cc
+++ b/chromium/ui/aura/scoped_keyboard_hook.cc
@@ -9,6 +9,8 @@
namespace aura {
+ScopedKeyboardHook::ScopedKeyboardHook() = default;
+
ScopedKeyboardHook::ScopedKeyboardHook(
base::WeakPtr<WindowTreeHost> window_tree_host)
: window_tree_host_(window_tree_host) {
@@ -21,4 +23,8 @@ ScopedKeyboardHook::~ScopedKeyboardHook() {
window_tree_host_->ReleaseSystemKeyEventCapture();
}
+bool ScopedKeyboardHook::IsKeyLocked(int native_key_code) {
+ return window_tree_host_ && window_tree_host_->IsKeyLocked(native_key_code);
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/scoped_keyboard_hook.h b/chromium/ui/aura/scoped_keyboard_hook.h
index d061544aff2..57975d68c91 100644
--- a/chromium/ui/aura/scoped_keyboard_hook.h
+++ b/chromium/ui/aura/scoped_keyboard_hook.h
@@ -20,7 +20,13 @@ class WindowTreeHost;
class AURA_EXPORT ScopedKeyboardHook {
public:
explicit ScopedKeyboardHook(base::WeakPtr<WindowTreeHost> weak_ptr);
- ~ScopedKeyboardHook();
+ virtual ~ScopedKeyboardHook();
+
+ // True if |native_key_code| is reserved for an active KeyboardLock request.
+ virtual bool IsKeyLocked(int native_key_code);
+
+ protected:
+ ScopedKeyboardHook();
private:
THREAD_CHECKER(thread_checker_);
diff --git a/chromium/ui/aura/test/ui_controls_factory_ozone.cc b/chromium/ui/aura/test/ui_controls_factory_ozone.cc
index c30653ca6c0..38391290fe3 100644
--- a/chromium/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/chromium/ui/aura/test/ui_controls_factory_ozone.cc
@@ -8,9 +8,14 @@
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
+#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/env.h"
+#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/test/aura_test_utils.h"
+#include "ui/aura/test/env_test_helper.h"
#include "ui/aura/test/ui_controls_factory_aura.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/test/ui_controls_aura.h"
@@ -21,6 +26,15 @@ namespace aura {
namespace test {
namespace {
+// Callback from Window Service with the result of posting an event. |result|
+// is true if event successfully processed and |closure| is an optional closure
+// to run when done (used in client code to wait for ack).
+void OnWindowServiceProcessedEvent(base::OnceClosure closure, bool result) {
+ DCHECK(result);
+ if (closure)
+ std::move(closure).Run();
+}
+
class UIControlsOzone : public ui_controls::UIControlsAura {
public:
UIControlsOzone(WindowTreeHost* host) : host_(host) {}
@@ -31,73 +45,83 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
bool shift,
bool alt,
bool command) override {
- return SendKeyPressNotifyWhenDone(
- window, key, control, shift, alt, command, base::Closure());
+ return SendKeyPressNotifyWhenDone(window, key, control, shift, alt, command,
+ base::OnceClosure());
}
- bool SendKeyPressNotifyWhenDone(
- gfx::NativeWindow window,
- ui::KeyboardCode key,
- bool control,
- bool shift,
- bool alt,
- bool command,
- const base::Closure& closure) override {
+ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
+ ui::KeyboardCode key,
+ bool control,
+ bool shift,
+ bool alt,
+ bool command,
+ base::OnceClosure closure) override {
int flags = button_down_mask_;
if (control) {
flags |= ui::EF_CONTROL_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, flags);
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, flags,
+ base::OnceClosure());
}
if (shift) {
flags |= ui::EF_SHIFT_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, flags);
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, flags,
+ base::OnceClosure());
}
if (alt) {
flags |= ui::EF_ALT_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_MENU, flags);
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_MENU, flags,
+ base::OnceClosure());
}
if (command) {
flags |= ui::EF_COMMAND_DOWN;
- PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LWIN, flags);
+ PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LWIN, flags,
+ base::OnceClosure());
}
- PostKeyEvent(ui::ET_KEY_PRESSED, key, flags);
- PostKeyEvent(ui::ET_KEY_RELEASED, key, flags);
+ PostKeyEvent(ui::ET_KEY_PRESSED, key, flags, base::OnceClosure());
+ const bool has_modifier = control || shift || alt || command;
+ // Pass the real closure to the last generated KeyEvent.
+ PostKeyEvent(ui::ET_KEY_RELEASED, key, flags,
+ has_modifier ? base::OnceClosure() : std::move(closure));
if (alt) {
flags &= ~ui::EF_ALT_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_MENU, flags);
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_MENU, flags,
+ (shift || control || command) ? base::OnceClosure()
+ : std::move(closure));
}
if (shift) {
flags &= ~ui::EF_SHIFT_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, flags);
+ PostKeyEvent(
+ ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, flags,
+ (control || command) ? base::OnceClosure() : std::move(closure));
}
if (control) {
flags &= ~ui::EF_CONTROL_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, flags);
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, flags,
+ command ? base::OnceClosure() : std::move(closure));
}
if (command) {
flags &= ~ui::EF_COMMAND_DOWN;
- PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LWIN, flags);
+ PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LWIN, flags,
+ std::move(closure));
}
- RunClosureAfterAllPendingUIEvents(closure);
return true;
}
bool SendMouseMove(long screen_x, long screen_y) override {
- return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure());
+ return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::OnceClosure());
}
- bool SendMouseMoveNotifyWhenDone(
- long screen_x,
- long screen_y,
- const base::Closure& closure) override {
+ bool SendMouseMoveNotifyWhenDone(long screen_x,
+ long screen_y,
+ base::OnceClosure closure) override {
gfx::Point root_location(screen_x, screen_y);
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(host_->window());
@@ -116,18 +140,17 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
else
event_type = ui::ET_MOUSE_MOVED;
- PostMouseEvent(event_type, host_location, button_down_mask_, 0);
+ PostMouseEvent(event_type, host_location, button_down_mask_, 0,
+ std::move(closure));
- RunClosureAfterAllPendingUIEvents(closure);
return true;
}
bool SendMouseEvents(ui_controls::MouseButton type, int state) override {
- return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
+ return SendMouseEventsNotifyWhenDone(type, state, base::OnceClosure());
}
- bool SendMouseEventsNotifyWhenDone(
- ui_controls::MouseButton type,
- int state,
- const base::Closure& closure) override {
+ bool SendMouseEventsNotifyWhenDone(ui_controls::MouseButton type,
+ int state,
+ base::OnceClosure closure) override {
gfx::Point root_location = aura::Env::GetInstance()->last_mouse_location();
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(host_->window());
@@ -158,65 +181,91 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
if (state & ui_controls::DOWN) {
button_down_mask_ |= flag;
- PostMouseEvent(ui::ET_MOUSE_PRESSED, host_location,
- button_down_mask_ | flag, flag);
+ // Pass the real closure to the last generated MouseEvent.
+ PostMouseEvent(
+ ui::ET_MOUSE_PRESSED, host_location, button_down_mask_ | flag, flag,
+ (state & ui_controls::UP) ? base::OnceClosure() : std::move(closure));
}
if (state & ui_controls::UP) {
button_down_mask_ &= ~flag;
PostMouseEvent(ui::ET_MOUSE_RELEASED, host_location,
- button_down_mask_ | flag, flag);
+ button_down_mask_ | flag, flag, std::move(closure));
}
- RunClosureAfterAllPendingUIEvents(closure);
return true;
}
bool SendMouseClick(ui_controls::MouseButton type) override {
return SendMouseEvents(type, ui_controls::UP | ui_controls::DOWN);
}
- void RunClosureAfterAllPendingUIEvents(
- const base::Closure& closure) override {
- if (!closure.is_null())
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
- }
private:
- void SendEventToSink(ui::Event* event) {
- ui::EventSourceTestApi event_source_test(host_->GetEventSource());
- ui::EventDispatchDetails details = event_source_test.SendEventToSink(event);
- if (details.dispatcher_destroyed)
+ void SendEventToSink(ui::Event* event, base::OnceClosure closure) {
+ if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS) {
+ std::unique_ptr<ui::Event> event_to_send;
+ if (event->IsMouseEvent()) {
+ // WindowService expects MouseEvents as PointerEvents.
+ // See http://crbug.com/617222.
+ event_to_send =
+ std::make_unique<ui::PointerEvent>(*event->AsMouseEvent());
+ } else {
+ event_to_send = ui::Event::Clone(*event);
+ }
+
+ GetEventInjector()->InjectEvent(
+ host_->GetDisplayId(), std::move(event_to_send),
+ base::BindOnce(&OnWindowServiceProcessedEvent, std::move(closure)));
return;
+ }
+
+ // Post the task before processing the event. This is necessary in case
+ // processing the event results in a nested message loop.
+ if (closure) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(closure));
+ }
+
+ ui::EventSourceTestApi event_source_test(host_->GetEventSource());
+ ignore_result(event_source_test.SendEventToSink(event));
}
- void PostKeyEvent(ui::EventType type, ui::KeyboardCode key_code, int flags) {
+ void PostKeyEvent(ui::EventType type,
+ ui::KeyboardCode key_code,
+ int flags,
+ base::OnceClosure closure) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&UIControlsOzone::PostKeyEventTask,
- base::Unretained(this), type, key_code, flags));
+ FROM_HERE, base::BindOnce(&UIControlsOzone::PostKeyEventTask,
+ base::Unretained(this), type, key_code, flags,
+ std::move(closure)));
}
void PostKeyEventTask(ui::EventType type,
ui::KeyboardCode key_code,
- int flags) {
+ int flags,
+ base::OnceClosure closure) {
// Do not rewrite injected events. See crbug.com/136465.
flags |= ui::EF_FINAL;
ui::KeyEvent key_event(type, key_code, flags);
- SendEventToSink(&key_event);
+ SendEventToSink(&key_event, std::move(closure));
}
void PostMouseEvent(ui::EventType type,
const gfx::Point& host_location,
int flags,
- int changed_button_flags) {
+ int changed_button_flags,
+ base::OnceClosure closure) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&UIControlsOzone::PostMouseEventTask, base::Unretained(this),
- type, host_location, flags, changed_button_flags));
+ base::BindOnce(&UIControlsOzone::PostMouseEventTask,
+ base::Unretained(this), type, host_location, flags,
+ changed_button_flags, std::move(closure)));
}
void PostMouseEventTask(ui::EventType type,
const gfx::Point& host_location,
int flags,
- int changed_button_flags) {
+ int changed_button_flags,
+ base::OnceClosure closure) {
ui::MouseEvent mouse_event(type, host_location, host_location,
ui::EventTimeForNow(), flags,
changed_button_flags);
@@ -224,10 +273,25 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
// This hack is necessary to set the repeat count for clicks.
ui::MouseEvent mouse_event2(&mouse_event);
- SendEventToSink(&mouse_event2);
+ SendEventToSink(&mouse_event2, std::move(closure));
+ }
+
+ // Returns the ui::mojom::EventInjector, which is used to send events
+ // to the Window Service for dispatch.
+ ui::mojom::EventInjector* GetEventInjector() {
+ DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstance()->mode());
+ if (!event_injector_) {
+ DCHECK(aura::test::EnvTestHelper().GetWindowTreeClient());
+ aura::test::EnvTestHelper()
+ .GetWindowTreeClient()
+ ->connector()
+ ->BindInterface(ui::mojom::kServiceName, &event_injector_);
+ }
+ return event_injector_.get();
}
WindowTreeHost* host_;
+ ui::mojom::EventInjectorPtr event_injector_;
// Mask of the mouse buttons currently down. This is static as it needs to
// track the state globally for all displays. A UIControlsOzone instance is
diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc
index 0f224d897e0..c8b3654b21c 100644
--- a/chromium/ui/aura/window.cc
+++ b/chromium/ui/aura/window.cc
@@ -14,7 +14,6 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -274,9 +273,7 @@ void Window::SetTransform(const gfx::Transform& transform) {
WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion_tracking;
for (WindowObserver& observer : observers_)
observer.OnWindowTargetTransformChanging(this, transform);
- gfx::Transform old_transform = layer()->transform();
layer()->SetTransform(transform);
- port_->OnDidChangeTransform(old_transform, transform);
}
void Window::SetLayoutManager(LayoutManager* layout_manager) {
@@ -767,6 +764,17 @@ void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
}
}
+void Window::SetDeviceScaleFactor(float device_scale_factor) {
+ float old_device_scale_factor = layer()->device_scale_factor();
+ layer()->OnDeviceScaleFactorChanged(device_scale_factor);
+
+ // If we are currently not the layer's delegate, we will not get the device
+ // scale factor changed notification from the layer (this typically happens
+ // after animating hidden). We must notify ourselves.
+ if (layer()->delegate() != this)
+ OnDeviceScaleFactorChanged(old_device_scale_factor, device_scale_factor);
+}
+
void Window::SetVisible(bool visible) {
if (visible == layer()->GetTargetVisibility())
return; // No change.
@@ -1100,6 +1108,15 @@ void Window::AllocateLocalSurfaceId() {
port_->AllocateLocalSurfaceId();
}
+bool Window::IsLocalSurfaceIdAllocationSuppressed() const {
+ return port_->IsLocalSurfaceIdAllocationSuppressed();
+}
+
+viz::ScopedSurfaceIdAllocator Window::GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) {
+ return port_->GetSurfaceIdAllocator(std::move(allocation_task));
+}
+
const viz::LocalSurfaceId& Window::GetLocalSurfaceId() const {
return port_->GetLocalSurfaceId();
}
@@ -1153,7 +1170,9 @@ void Window::OnLayerOpacityChanged(ui::PropertyChangeReason reason) {
observer.OnWindowOpacitySet(this, reason);
}
-void Window::OnLayerTransformed(ui::PropertyChangeReason reason) {
+void Window::OnLayerTransformed(const gfx::Transform& old_transform,
+ ui::PropertyChangeReason reason) {
+ port_->OnDidChangeTransform(old_transform, layer()->transform());
WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion_tracking;
for (WindowObserver& observer : observers_)
observer.OnWindowTransformed(this, reason);
diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h
index b6e2dcfb871..8fb95e8e14f 100644
--- a/chromium/ui/aura/window.h
+++ b/chromium/ui/aura/window.h
@@ -19,9 +19,11 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/strings/string16.h"
+#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/window_types.h"
#include "ui/aura/window_observer.h"
+#include "ui/aura/window_port.h"
#include "ui/base/class_property.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/layer_delegate.h"
@@ -58,7 +60,6 @@ class LayoutManager;
class ScopedKeyboardHook;
class WindowDelegate;
class WindowObserver;
-class WindowPort;
class WindowPortForShutdown;
class WindowTreeHost;
@@ -216,6 +217,11 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// LayoutManager may adjust the bounds.
void SetBounds(const gfx::Rect& new_bounds);
+ // Explicitly set a device scale factor for the window. Note that the
+ // window's device scale factor is also set when adding its ui::Layer to the
+ // layer tree of a ui::Compositor.
+ void SetDeviceScaleFactor(float device_scale_factor);
+
// Changes the bounds of the window in the screen coordinates.
// If present, the window's parent's LayoutManager may adjust the bounds.
void SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen_coords,
@@ -386,6 +392,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// that does not involve a resize or a device scale factor change.
void AllocateLocalSurfaceId();
+ // When a child-allocated viz::LocalSurfaceId is being processed, this returns
+ // true.
+ bool IsLocalSurfaceIdAllocationSuppressed() const;
+
+ viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task);
+
// Gets the current viz::LocalSurfaceId.
const viz::LocalSurfaceId& GetLocalSurfaceId() const;
@@ -518,7 +531,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
void OnPaintLayer(const ui::PaintContext& context) override;
void OnLayerBoundsChanged(const gfx::Rect& old_bounds,
ui::PropertyChangeReason reason) override;
- void OnLayerTransformed(ui::PropertyChangeReason reason) override;
+ void OnLayerTransformed(const gfx::Transform& old_transform,
+ ui::PropertyChangeReason reason) override;
void OnLayerOpacityChanged(ui::PropertyChangeReason reason) override;
// Overridden from ui::EventTarget:
diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc
index 8bfba9421b2..31f80f2e704 100644
--- a/chromium/ui/aura/window_event_dispatcher.cc
+++ b/chromium/ui/aura/window_event_dispatcher.cc
@@ -131,7 +131,8 @@ void WindowEventDispatcher::RepostEvent(const ui::LocatedEvent* event) {
if (held_repostable_event_) {
base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
- FROM_HERE, base::Bind(
+ FROM_HERE,
+ base::BindOnce(
base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
repost_event_factory_.GetWeakPtr()));
}
@@ -823,8 +824,8 @@ void WindowEventDispatcher::PostSynthesizeMouseMove() {
synthesize_mouse_move_ = true;
base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
FROM_HERE,
- base::Bind(base::IgnoreResult(
- &WindowEventDispatcher::SynthesizeMouseMoveEvent),
+ base::BindOnce(
+ base::IgnoreResult(&WindowEventDispatcher::SynthesizeMouseMoveEvent),
held_event_factory_.GetWeakPtr()));
}
diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc
index dc9571ef34e..fb63240663b 100644
--- a/chromium/ui/aura/window_event_dispatcher_unittest.cc
+++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc
@@ -2158,8 +2158,9 @@ class WindowEventDispatcherTestWithMessageLoop
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE));
message_loop()->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&WindowEventDispatcherTestWithMessageLoop::RepostEventHelper,
- host()->dispatcher(), base::Passed(&mouse)));
+ base::BindOnce(
+ &WindowEventDispatcherTestWithMessageLoop::RepostEventHelper,
+ host()->dispatcher(), std::move(mouse)));
message_loop()->task_runner()->PostTask(
FROM_HERE, message_loop()->QuitWhenIdleClosure());
@@ -2205,8 +2206,9 @@ TEST_P(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {
// Perform the test in a callback, so that it runs after the message-loop
// starts.
message_loop()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&WindowEventDispatcherTestWithMessageLoop::RunTest,
- base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&WindowEventDispatcherTestWithMessageLoop::RunTest,
+ base::Unretained(this)));
base::RunLoop().Run();
}
@@ -3205,8 +3207,8 @@ class NestedLocationDelegate : public test::TestWindowDelegate {
// is considered the first nested loop.
base::RunLoop run_loop;
base::MessageLoop::current()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&NestedLocationDelegate::InInitialMessageLoop,
- base::Unretained(this), &run_loop));
+ FROM_HERE, base::BindOnce(&NestedLocationDelegate::InInitialMessageLoop,
+ base::Unretained(this), &run_loop));
run_loop.Run();
}
@@ -3216,8 +3218,8 @@ class NestedLocationDelegate : public test::TestWindowDelegate {
// RunLoop.
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
base::MessageLoop::current()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&NestedLocationDelegate::InRunMessageLoop,
- base::Unretained(this), &run_loop));
+ FROM_HERE, base::BindOnce(&NestedLocationDelegate::InRunMessageLoop,
+ base::Unretained(this), &run_loop));
run_loop.Run();
initial_run_loop->Quit();
}
diff --git a/chromium/ui/aura/window_occlusion_tracker.cc b/chromium/ui/aura/window_occlusion_tracker.cc
index dff18bd85e7..f573b75c057 100644
--- a/chromium/ui/aura/window_occlusion_tracker.cc
+++ b/chromium/ui/aura/window_occlusion_tracker.cc
@@ -27,7 +27,11 @@ constexpr ui::LayerAnimationElement::AnimatableProperties
// Maximum number of times that MaybeComputeOcclusion() should have to recompute
// occlusion states before they become stable.
-constexpr int kMaxRecomputeOcclusion = 2;
+//
+// TODO(fdoray): This can be changed to 2 once showing/hiding a WebContents
+// doesn't cause a call to Show()/Hide() on the aura::Window of a
+// RenderWidgetHostViewAura. https://crbug.com/827268
+constexpr int kMaxRecomputeOcclusion = 3;
WindowOcclusionTracker* g_tracker = nullptr;
@@ -132,6 +136,11 @@ WindowOcclusionTracker::WindowOcclusionTracker() = default;
WindowOcclusionTracker::~WindowOcclusionTracker() = default;
+WindowOcclusionTracker* WindowOcclusionTracker::GetInstance() {
+ DCHECK(g_tracker);
+ return g_tracker;
+}
+
void WindowOcclusionTracker::MaybeComputeOcclusion() {
if (g_num_pause_occlusion_tracking || num_times_occlusion_recomputed_ != 0)
return;
@@ -352,8 +361,10 @@ void WindowOcclusionTracker::MarkRootWindowAsDirty(
// TODO(fdoray): Remove this once we are confident that occlusion states are
// stable after |kMaxRecomputeOcclusion| iterations in production.
// https://crbug.com/813076
- if (num_times_occlusion_recomputed_ == kMaxRecomputeOcclusion)
+ if (num_times_occlusion_recomputed_ == kMaxRecomputeOcclusion) {
+ was_occlusion_recomputed_too_many_times_ = true;
base::debug::DumpWithoutCrashing();
+ }
}
bool WindowOcclusionTracker::WindowOrParentIsAnimated(Window* window) const {
@@ -490,8 +501,13 @@ void WindowOcclusionTracker::OnWillRemoveWindow(Window* window) {
void WindowOcclusionTracker::OnWindowVisibilityChanged(Window* window,
bool visible) {
- MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(
- window, [=]() { return !WindowOrParentIsAnimated(window); });
+ MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(window, [=]() {
+ // A child isn't visible when its parent isn't IsVisible(). Therefore, there
+ // is no need to compute occlusion when Show() or Hide() is called on a
+ // window with a hidden parent.
+ return (!window->parent() || window->parent()->IsVisible()) &&
+ !WindowOrParentIsAnimated(window);
+ });
}
void WindowOcclusionTracker::OnWindowBoundsChanged(
diff --git a/chromium/ui/aura/window_occlusion_tracker.h b/chromium/ui/aura/window_occlusion_tracker.h
index c76f4f4eee0..f60948420bd 100644
--- a/chromium/ui/aura/window_occlusion_tracker.h
+++ b/chromium/ui/aura/window_occlusion_tracker.h
@@ -22,6 +22,10 @@ class Transform;
namespace aura {
+namespace test {
+class WindowOcclusionTrackerTestApi;
+}
+
// Notifies tracked Windows when their occlusion state change.
//
// To start tracking the occlusion state of a Window, call
@@ -54,6 +58,8 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
static void Track(Window* window);
private:
+ friend class test::WindowOcclusionTrackerTestApi;
+
struct RootWindowState {
// Number of Windows whose occlusion state is tracked under this root
// Window.
@@ -66,6 +72,8 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
WindowOcclusionTracker();
~WindowOcclusionTracker() override;
+ static WindowOcclusionTracker* GetInstance();
+
// Recomputes the occlusion state of tracked windows under roots marked as
// dirty in |root_windows_| if there are no active
// ScopedPauseOcclusionTracking instance.
@@ -194,6 +202,11 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// recomputed occlusion states. Always 0 when not in MaybeComputeOcclusion().
int num_times_occlusion_recomputed_ = 0;
+ // Set to true when occlusion is recomputed too many times before it becomes
+ // stable. Reset in
+ // WindowOcclusionTrackerTestApi::WasOcclusionRecomputedTooManyTimes().
+ bool was_occlusion_recomputed_too_many_times_ = false;
+
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTracker);
};
diff --git a/chromium/ui/aura/window_occlusion_tracker_unittest.cc b/chromium/ui/aura/window_occlusion_tracker_unittest.cc
index 6394bd7e42f..a89b3ecd7aa 100644
--- a/chromium/ui/aura/window_occlusion_tracker_unittest.cc
+++ b/chromium/ui/aura/window_occlusion_tracker_unittest.cc
@@ -12,6 +12,7 @@
#include "ui/aura/test/env_test_helper.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
+#include "ui/aura/test/window_occlusion_tracker_test_api.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
@@ -1425,30 +1426,33 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
if (!window_to_update_)
return;
+ ++num_occlusion_change_;
+
if (window_to_update_->IsVisible()) {
window_to_update_->Hide();
- EXPECT_FALSE(did_set_expectation_from_occlusion_changed_);
- set_expectation(Window::OcclusionState::HIDDEN);
- did_set_expectation_from_occlusion_changed_ = true;
+ if (num_occlusion_change_ <= 3)
+ set_expectation(Window::OcclusionState::HIDDEN);
} else {
window_to_update_->Show();
- if (!did_set_expectation_from_occlusion_changed_)
set_expectation(Window::OcclusionState::VISIBLE);
}
}
private:
Window* window_to_update_ = nullptr;
- bool did_set_expectation_from_occlusion_changed_ = false;
+ int num_occlusion_change_ = 0;
DISALLOW_COPY_AND_ASSIGN(WindowDelegateChangingWindowVisibility);
};
+
} // namespace
// Verify that if a window changes its visibility every time it is notified that
// its occlusion state changed, the occlusion state of all IsVisible() windows
-// is set to NOT_OCCLUDED and no infinite loop is entered.
+// is set to VISIBLE and no infinite loop is entered.
TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
+ test::WindowOcclusionTrackerTestApi test_api;
+
// Create 2 superposed tracked windows.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
@@ -1484,15 +1488,17 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
// Hide |window_d|. This will cause occlusion to be recomputed multiple times.
// Once the maximum number of times that occlusion can be recomputed is
// reached, the occlusion state of all IsVisible() windows should be set to
- // NOT_OCCLUDED.
+ // VISIBLE.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_d->set_expectation(Window::OcclusionState::HIDDEN);
+ EXPECT_FALSE(test_api.WasOcclusionRecomputedTooManyTimes());
window_d->Hide();
+ EXPECT_TRUE(test_api.WasOcclusionRecomputedTooManyTimes());
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_d->is_expecting_call());
}
-// Verify that the occlusion states are correctly update when a branch of the
+// Verify that the occlusion states are correctly updated when a branch of the
// tree is hidden.
TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
// Create a branch of 3 tracked windows. Expect them to be visible.
@@ -1521,4 +1527,92 @@ TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
EXPECT_FALSE(delegate_c->is_expecting_call());
}
+namespace {
+
+class WindowDelegateHidingWindow : public MockWindowDelegate {
+ public:
+ WindowDelegateHidingWindow() = default;
+
+ void set_window_to_update(Window* window) { window_to_update_ = window; }
+
+ // MockWindowDelegate:
+ void OnWindowOcclusionChanged(
+ Window::OcclusionState occlusion_state) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ if (!window_to_update_)
+ return;
+
+ window_to_update_->Hide();
+ }
+
+ private:
+ Window* window_to_update_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowDelegateHidingWindow);
+};
+
+class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
+ public:
+ WindowDelegateAddingAndHidingChild(WindowOcclusionTrackerTest* test)
+ : test_(test) {}
+
+ void set_window_to_update(Window* window) { window_to_update_ = window; }
+
+ // MockWindowDelegate:
+ void OnWindowOcclusionChanged(
+ Window::OcclusionState occlusion_state) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+
+ if (!window_to_update_)
+ return;
+
+ // Create a child window and hide it. Since this code runs when occlusion
+ // has already been recomputed twice, if one of the operations below causes
+ // occlusion to be recomputed, the test will fail with a DCHECK.
+ Window* window =
+ test_->CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5), window_to_update_);
+ window->Hide();
+ }
+
+ private:
+ WindowOcclusionTrackerTest* test_;
+ Window* window_to_update_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowDelegateAddingAndHidingChild);
+};
+
+} // namespace
+
+// Verify that hiding a window that has a hidden parent doesn't cause occlusion
+// to be recomputed.
+TEST_F(WindowOcclusionTrackerTest,
+ HideWindowWithHiddenParentOnOcclusionChange) {
+ test::WindowOcclusionTrackerTestApi test_api;
+
+ auto* delegate_a = new WindowDelegateAddingAndHidingChild(this);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ auto* delegate_b = new WindowDelegateHidingWindow();
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+
+ // When |window_b| is hidden, it will hide |window_a|. |window_a| will in turn
+ // add a child to itself and hide it.
+ delegate_a->set_window_to_update(window_a);
+ delegate_b->set_window_to_update(window_a);
+
+ delegate_a->set_expectation(Window::OcclusionState::HIDDEN);
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
+ EXPECT_FALSE(test_api.WasOcclusionRecomputedTooManyTimes());
+ window_b->Hide();
+ // Hiding a child to |window_a| and hiding it shouldn't cause occlusion to be
+ // recomputed too many times.
+ EXPECT_FALSE(test_api.WasOcclusionRecomputedTooManyTimes());
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window_port.h b/chromium/ui/aura/window_port.h
index a57c5134920..91e6445fcca 100644
--- a/chromium/ui/aura/window_port.h
+++ b/chromium/ui/aura/window_port.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
+#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "ui/aura/aura_export.h"
#include "ui/base/class_property.h"
@@ -90,6 +91,18 @@ class AURA_EXPORT WindowPort {
// that does not involve a resize or a device scale factor change.
virtual void AllocateLocalSurfaceId() = 0;
+ // When a child-allocated viz::LocalSurfaceId is being processed, this returns
+ // true.
+ virtual bool IsLocalSurfaceIdAllocationSuppressed() const = 0;
+
+ // When a ScopedSurfaceIdAllocator is alive, it prevents the
+ // allocator from actually allocating. Instead, it triggers its
+ // |allocation_task| upon destruction. This allows us to issue only one
+ // allocation during the lifetime. This is used to continue routing and
+ // processing when a child allocates its own LocalSurfaceId.
+ virtual viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) = 0;
+
// Gets the current viz::LocalSurfaceId. The viz::LocalSurfaceId is allocated
// lazily on call, and will be updated on changes to size or device scale
// factor.
diff --git a/chromium/ui/aura/window_port_for_shutdown.cc b/chromium/ui/aura/window_port_for_shutdown.cc
index a11a2eed846..1b47442ed6c 100644
--- a/chromium/ui/aura/window_port_for_shutdown.cc
+++ b/chromium/ui/aura/window_port_for_shutdown.cc
@@ -4,7 +4,6 @@
#include "ui/aura/window_port_for_shutdown.h"
-#include "base/memory/ptr_util.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "ui/aura/window.h"
@@ -59,6 +58,15 @@ WindowPortForShutdown::CreateLayerTreeFrameSink() {
void WindowPortForShutdown::AllocateLocalSurfaceId() {}
+bool WindowPortForShutdown::IsLocalSurfaceIdAllocationSuppressed() const {
+ return false;
+}
+
+viz::ScopedSurfaceIdAllocator WindowPortForShutdown::GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) {
+ return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
+}
+
const viz::LocalSurfaceId& WindowPortForShutdown::GetLocalSurfaceId() {
return local_surface_id_;
}
diff --git a/chromium/ui/aura/window_port_for_shutdown.h b/chromium/ui/aura/window_port_for_shutdown.h
index e3d97a5b64d..2027fccbecc 100644
--- a/chromium/ui/aura/window_port_for_shutdown.h
+++ b/chromium/ui/aura/window_port_for_shutdown.h
@@ -40,6 +40,9 @@ class WindowPortForShutdown : public WindowPort {
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
+ bool IsLocalSurfaceIdAllocationSuppressed() const override;
+ viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
+ base::OnceCallback<void()> allocation_task) override;
const viz::LocalSurfaceId& GetLocalSurfaceId() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc
index f8dbba61c78..c40ef77ed70 100644
--- a/chromium/ui/aura/window_targeter.cc
+++ b/chromium/ui/aura/window_targeter.cc
@@ -47,6 +47,22 @@ WindowTargeter::GetExtraHitTestShapeRects(Window* target) const {
return nullptr;
}
+void WindowTargeter::SetInsets(const gfx::Insets& mouse_and_touch_extend) {
+ SetInsets(mouse_and_touch_extend, mouse_and_touch_extend);
+}
+
+void WindowTargeter::SetInsets(const gfx::Insets& mouse_extend,
+ const gfx::Insets& touch_extend) {
+ if (mouse_extend_ == mouse_extend && touch_extend_ == touch_extend)
+ return;
+
+ const gfx::Insets last_mouse_extend_ = mouse_extend_;
+ const gfx::Insets last_touch_extend_ = touch_extend_;
+ mouse_extend_ = mouse_extend;
+ touch_extend_ = touch_extend;
+ OnSetInsets(last_mouse_extend_, last_touch_extend_);
+}
+
Window* WindowTargeter::GetPriorityTargetInRootWindow(
Window* root_window,
const ui::LocatedEvent& event) {
@@ -256,18 +272,6 @@ bool WindowTargeter::ShouldUseExtendedBounds(const aura::Window* window) const {
void WindowTargeter::OnSetInsets(const gfx::Insets& last_mouse_extend,
const gfx::Insets& last_touch_extend) {}
-void WindowTargeter::SetInsets(const gfx::Insets& mouse_extend,
- const gfx::Insets& touch_extend) {
- if (mouse_extend_ == mouse_extend && touch_extend_ == touch_extend)
- return;
-
- const gfx::Insets last_mouse_extend_ = mouse_extend_;
- const gfx::Insets last_touch_extend_ = touch_extend_;
- mouse_extend_ = mouse_extend;
- touch_extend_ = touch_extend;
- OnSetInsets(last_mouse_extend_, last_touch_extend_);
-}
-
Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
const ui::KeyEvent& key) {
Window* root_window = window->GetRootWindow();
diff --git a/chromium/ui/aura/window_targeter.h b/chromium/ui/aura/window_targeter.h
index f03c5b7c54e..ead1801cf50 100644
--- a/chromium/ui/aura/window_targeter.h
+++ b/chromium/ui/aura/window_targeter.h
@@ -60,6 +60,12 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
virtual std::unique_ptr<HitTestRects> GetExtraHitTestShapeRects(
Window* target) const;
+ // Sets additional mouse and touch insets that are factored into the hit-test
+ // regions returned by GetHitTestRects.
+ void SetInsets(const gfx::Insets& mouse_and_touch_extend);
+ void SetInsets(const gfx::Insets& mouse_extend,
+ const gfx::Insets& touch_extend);
+
// If there is a target that takes priority over normal WindowTargeter (such
// as a capture window) this returns it.
Window* GetPriorityTargetInRootWindow(Window* root_window,
@@ -115,11 +121,6 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
virtual void OnSetInsets(const gfx::Insets& last_mouse_extend,
const gfx::Insets& last_touch_extend);
- // Sets additional mouse and touch insets that are factored into the hit-test
- // regions returned by GetHitTestRects.
- void SetInsets(const gfx::Insets& mouse_extend,
- const gfx::Insets& touch_extend);
-
const gfx::Insets& mouse_extend() const { return mouse_extend_; }
const gfx::Insets& touch_extend() const { return touch_extend_; }
diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc
index cbade2495bb..64e336c6ca5 100644
--- a/chromium/ui/aura/window_tree_host.cc
+++ b/chromium/ui/aura/window_tree_host.cc
@@ -61,8 +61,12 @@ WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
}
void WindowTreeHost::InitHost() {
+ display::Display display =
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+ device_scale_factor_ = display.device_scale_factor();
+
InitCompositor();
- UpdateRootWindowSizeInPixels(GetBoundsInPixels().size());
+ UpdateRootWindowSizeInPixels();
Env::GetInstance()->NotifyHostInitialized(this);
}
@@ -79,16 +83,15 @@ ui::EventSink* WindowTreeHost::event_sink() {
}
gfx::Transform WindowTreeHost::GetRootTransform() const {
- float scale = ui::GetDeviceScaleFactor(window()->layer());
gfx::Transform transform;
- transform.Scale(scale, scale);
+ transform.Scale(device_scale_factor_, device_scale_factor_);
transform *= window()->layer()->transform();
return transform;
}
void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) {
window()->SetTransform(transform);
- UpdateRootWindowSizeInPixels(GetBoundsInPixels().size());
+ UpdateRootWindowSizeInPixels();
}
gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
@@ -113,25 +116,11 @@ gfx::Transform WindowTreeHost::GetInverseRootTransformForLocalEventCoordinates()
return invert;
}
-void WindowTreeHost::SetOutputSurfacePaddingInPixels(
- const gfx::Insets& padding_in_pixels) {
- if (output_surface_padding_in_pixels_ == padding_in_pixels)
- return;
-
- output_surface_padding_in_pixels_ = padding_in_pixels;
- OnHostResizedInPixels(GetBoundsInPixels().size());
-}
-
-void WindowTreeHost::UpdateRootWindowSizeInPixels(
- const gfx::Size& host_size_in_pixels) {
- gfx::Rect bounds(output_surface_padding_in_pixels_.left(),
- output_surface_padding_in_pixels_.top(),
- host_size_in_pixels.width(), host_size_in_pixels.height());
- float scale_factor = ui::GetDeviceScaleFactor(window()->layer());
- gfx::RectF new_bounds =
- gfx::ScaleRect(gfx::RectF(bounds), 1.0f / scale_factor);
- window()->layer()->transform().TransformRect(&new_bounds);
- window()->SetBounds(gfx::ToEnclosingRect(new_bounds));
+void WindowTreeHost::UpdateRootWindowSizeInPixels() {
+ gfx::Rect transformed_bounds_in_pixels =
+ GetTransformedRootWindowBoundsInPixels(GetBoundsInPixels().size());
+ window()->SetBounds(transformed_bounds_in_pixels);
+ window()->SetDeviceScaleFactor(device_scale_factor_);
}
void WindowTreeHost::ConvertDIPToScreenInPixels(gfx::Point* point) const {
@@ -319,12 +308,12 @@ void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
void WindowTreeHost::InitCompositor() {
DCHECK(!compositor_->root_layer());
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- compositor_->SetScaleAndSize(display.device_scale_factor(),
- GetBoundsInPixels().size(),
+ compositor_->SetScaleAndSize(device_scale_factor_, GetBoundsInPixels().size(),
window()->GetLocalSurfaceId());
compositor_->SetRootLayer(window()->layer());
+
+ display::Display display =
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window());
compositor_->SetDisplayColorSpace(display.color_space());
}
@@ -345,19 +334,19 @@ void WindowTreeHost::OnHostMovedInPixels(
void WindowTreeHost::OnHostResizedInPixels(
const gfx::Size& new_size_in_pixels) {
- gfx::Size adjusted_size(new_size_in_pixels);
- adjusted_size.Enlarge(output_surface_padding_in_pixels_.width(),
- output_surface_padding_in_pixels_.height());
+ display::Display display =
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+ device_scale_factor_ = display.device_scale_factor();
+
+ // The layer, and the observers should be notified of the
+ // transformed size of the root window.
+ UpdateRootWindowSizeInPixels();
// The compositor should have the same size as the native root window host.
// Get the latest scale from display because it might have been changed.
- compositor_->SetScaleAndSize(ui::GetScaleFactorForNativeView(window()),
- adjusted_size, window()->GetLocalSurfaceId());
+ compositor_->SetScaleAndSize(device_scale_factor_, new_size_in_pixels,
+ window()->GetLocalSurfaceId());
- gfx::Size layer_size = GetBoundsInPixels().size();
- // The layer, and the observers should be notified of the
- // transformed size of the root window.
- UpdateRootWindowSizeInPixels(layer_size);
for (WindowTreeHostObserver& observer : observers_)
observer.OnHostResized(this);
}
@@ -415,6 +404,15 @@ void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
}
}
+gfx::Rect WindowTreeHost::GetTransformedRootWindowBoundsInPixels(
+ const gfx::Size& size_in_pixels) const {
+ gfx::Rect bounds(size_in_pixels);
+ gfx::RectF new_bounds =
+ gfx::ScaleRect(gfx::RectF(bounds), 1.0f / device_scale_factor_);
+ window()->layer()->transform().TransformRect(&new_bounds);
+ return gfx::ToEnclosingRect(new_bounds);
+}
+
////////////////////////////////////////////////////////////////////////////////
// WindowTreeHost, private:
diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h
index 4a3e90b7b55..83c144432b3 100644
--- a/chromium/ui/aura/window_tree_host.h
+++ b/chromium/ui/aura/window_tree_host.h
@@ -10,7 +10,6 @@
#include <memory>
#include "base/containers/flat_set.h"
-#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -22,11 +21,10 @@
#include "ui/compositor/compositor_observer.h"
#include "ui/display/display_observer.h"
#include "ui/events/event_source.h"
-#include "ui/gfx/geometry/insets.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
-class Insets;
class Point;
class Rect;
class Size;
@@ -98,21 +96,12 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
virtual gfx::Transform GetInverseRootTransformForLocalEventCoordinates()
const;
- // Sets padding applied to the output surface. The output surface is sized to
- // to the size of the host plus output surface padding. |window()| is offset
- // by |padding_in_pixels|, that is, |window|'s origin is set to
- // padding_in_pixels.left(), padding_in_pixels.top().
- // This does not impact the bounds as returned from GetBounds(), only the
- // output surface size and location of window(). Additionally window() is
- // sized to the size set by bounds (more specifically the size passed to
- // OnHostResizedInPixels()), but the location of window() is set to that of
- // |padding_in_pixels|.
- void SetOutputSurfacePaddingInPixels(const gfx::Insets& padding_in_pixels);
-
// Updates the root window's size using |host_size_in_pixels|, current
// transform and outsets.
- virtual void UpdateRootWindowSizeInPixels(
- const gfx::Size& host_size_in_pixels);
+ // TODO(ccameron): Make this function no longer public. The interaction
+ // between this call, GetBounds, and OnHostResizedInPixels is ambiguous and
+ // allows for inconsistencies.
+ void UpdateRootWindowSizeInPixels();
// Converts |point| from the root window's coordinate system to native
// screen's.
@@ -192,6 +181,11 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void Hide();
// Gets/Sets the size of the WindowTreeHost (in pixels).
+ // TODO(ccameron): The existence of OnHostMoved/ResizedInPixels and this
+ // function create confusion as to the source of the true bounds. Should it
+ // be expected that this will always return the values most recently
+ // specified by OnHostMoved/ResizedInPixels? If so, why do we ask the
+ // sub-classes to return the value when this class already knows the value?
virtual gfx::Rect GetBoundsInPixels() const = 0;
virtual void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels) = 0;
@@ -201,6 +195,10 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Releases OS capture of the root window.
virtual void ReleaseCapture() = 0;
+ // Returns the device scale assumed by the WindowTreeHost (set during the
+ // most recent call to OnHostResizedInPixels).
+ float device_scale_factor() const { return device_scale_factor_; }
+
// Requests that |keys| be intercepted at the platform level and routed
// directly to the web content. If |keys| is empty, all keys will be
// intercepted. Returns a ScopedKeyboardHook instance which stops capturing
@@ -232,6 +230,9 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
virtual gfx::Point GetLocationOnScreenInPixels() const = 0;
void OnHostMovedInPixels(const gfx::Point& new_location_in_pixels);
+ // TODO(ccameron): This needs to specify a device scale factor. It should
+ // arguably be merged with OnHostMovedInPixels (since all callers are pulling
+ // the size or position from a rect which also feeds OnHostMovedInPixels).
void OnHostResizedInPixels(const gfx::Size& new_size_in_pixels);
void OnHostWorkspaceChanged();
void OnHostDisplayChanged();
@@ -271,7 +272,12 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Stops capturing system keyboard events.
virtual void ReleaseSystemKeyEventCapture() = 0;
- protected:
+ // True if |native_key_code| is reserved for an active KeyboardLock request.
+ virtual bool IsKeyLocked(int native_key_code) = 0;
+
+ virtual gfx::Rect GetTransformedRootWindowBoundsInPixels(
+ const gfx::Size& size_in_pixels) const;
+
const base::ObserverList<WindowTreeHostObserver>& observers() const {
return observers_;
}
@@ -305,6 +311,11 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
std::unique_ptr<ui::Compositor> compositor_;
+ // The device scale factor is snapshotted in OnHostResizedInPixels.
+ // TODO(ccameron): The size and location from OnHostResizedInPixels and
+ // OnHostMovedInPixels should be snapshotted here as well.
+ float device_scale_factor_ = 1.f;
+
// Last cursor set. Used for testing.
gfx::NativeCursor last_cursor_;
gfx::Point last_cursor_request_position_in_host_;
@@ -319,8 +330,6 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Whether the InputMethod instance is owned by this WindowTreeHost.
bool owned_input_method_;
- gfx::Insets output_surface_padding_in_pixels_;
-
// Set to the time the synchronization event began.
base::TimeTicks synchronization_start_time_;
diff --git a/chromium/ui/aura/window_tree_host_platform.cc b/chromium/ui/aura/window_tree_host_platform.cc
index 43294f6f232..892fabd5115 100644
--- a/chromium/ui/aura/window_tree_host_platform.cc
+++ b/chromium/ui/aura/window_tree_host_platform.cc
@@ -44,18 +44,7 @@ WindowTreeHostPlatform::WindowTreeHostPlatform(const gfx::Rect& bounds)
: WindowTreeHostPlatform() {
bounds_ = bounds;
CreateCompositor();
-#if defined(USE_OZONE)
- platform_window_ =
- ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
-#elif defined(OS_WIN)
- platform_window_.reset(new ui::WinWindow(this, bounds));
-#elif defined(OS_ANDROID)
- platform_window_.reset(new ui::PlatformWindowAndroid(this));
-#elif defined(USE_X11)
- platform_window_.reset(new ui::X11Window(this, bounds));
-#else
- NOTIMPLEMENTED();
-#endif
+ CreateAndSetDefaultPlatformWindow();
}
WindowTreeHostPlatform::WindowTreeHostPlatform()
@@ -67,6 +56,21 @@ WindowTreeHostPlatform::WindowTreeHostPlatform(
widget_(gfx::kNullAcceleratedWidget),
current_cursor_(ui::CursorType::kNull) {}
+void WindowTreeHostPlatform::CreateAndSetDefaultPlatformWindow() {
+#if defined(USE_OZONE)
+ platform_window_ =
+ ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds_);
+#elif defined(OS_WIN)
+ platform_window_.reset(new ui::WinWindow(this, bounds_));
+#elif defined(OS_ANDROID)
+ platform_window_.reset(new ui::PlatformWindowAndroid(this));
+#elif defined(USE_X11)
+ platform_window_.reset(new ui::X11Window(this, bounds_));
+#else
+ NOTIMPLEMENTED();
+#endif
+}
+
void WindowTreeHostPlatform::SetPlatformWindow(
std::unique_ptr<ui::PlatformWindow> window) {
platform_window_ = std::move(window);
@@ -116,12 +120,19 @@ void WindowTreeHostPlatform::ReleaseCapture() {
bool WindowTreeHostPlatform::CaptureSystemKeyEventsImpl(
base::Optional<base::flat_set<int>> native_key_codes) {
+ // TODO(680809): Implement as part of the KeyboardLock feature work.
NOTIMPLEMENTED();
return false;
}
void WindowTreeHostPlatform::ReleaseSystemKeyEventCapture() {}
+bool WindowTreeHostPlatform::IsKeyLocked(int native_key_code) {
+ // TODO(680809): Implement as part of the KeyboardLock feature work.
+ NOTIMPLEMENTED();
+ return false;
+}
+
void WindowTreeHostPlatform::SetCursorNative(gfx::NativeCursor cursor) {
if (cursor == current_cursor_)
return;
@@ -149,12 +160,10 @@ void WindowTreeHostPlatform::OnBoundsChanged(const gfx::Rect& new_bounds) {
float new_scale = ui::GetScaleFactorForNativeView(window());
gfx::Rect old_bounds = bounds_;
bounds_ = new_bounds;
- if (bounds_.origin() != old_bounds.origin()) {
+ if (bounds_.origin() != old_bounds.origin())
OnHostMovedInPixels(bounds_.origin());
- }
- if (bounds_.size() != old_bounds.size() || current_scale != new_scale) {
+ if (bounds_.size() != old_bounds.size() || current_scale != new_scale)
OnHostResizedInPixels(bounds_.size());
- }
}
void WindowTreeHostPlatform::OnDamageRect(const gfx::Rect& damage_rect) {
@@ -190,7 +199,9 @@ void WindowTreeHostPlatform::OnAcceleratedWidgetAvailable(
gfx::AcceleratedWidget widget,
float device_pixel_ratio) {
widget_ = widget;
- WindowTreeHost::OnAcceleratedWidgetAvailable();
+ // This may be called before the Compositor has been created.
+ if (compositor())
+ WindowTreeHost::OnAcceleratedWidgetAvailable();
}
void WindowTreeHostPlatform::OnAcceleratedWidgetDestroyed() {
diff --git a/chromium/ui/aura/window_tree_host_platform.h b/chromium/ui/aura/window_tree_host_platform.h
index 5935d1634b6..893a8da1035 100644
--- a/chromium/ui/aura/window_tree_host_platform.h
+++ b/chromium/ui/aura/window_tree_host_platform.h
@@ -48,8 +48,15 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,
WindowTreeHostPlatform();
explicit WindowTreeHostPlatform(std::unique_ptr<WindowPort> window_port);
+ // Creates a ui::PlatformWindow appropriate for the current platform and
+ // installs it at as the PlatformWindow for this WindowTreeHostPlatform.
+ void CreateAndSetDefaultPlatformWindow();
+
void SetPlatformWindow(std::unique_ptr<ui::PlatformWindow> window);
ui::PlatformWindow* platform_window() { return platform_window_.get(); }
+ const ui::PlatformWindow* platform_window() const {
+ return platform_window_.get();
+ }
// ui::PlatformWindowDelegate:
void OnBoundsChanged(const gfx::Rect& new_bounds) override;
@@ -66,6 +73,7 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,
bool CaptureSystemKeyEventsImpl(
base::Optional<base::flat_set<int>> native_key_codes) override;
void ReleaseSystemKeyEventCapture() override;
+ bool IsKeyLocked(int native_key_code) override;
private:
gfx::AcceleratedWidget widget_;
diff --git a/chromium/ui/aura/window_tree_host_unittest.cc b/chromium/ui/aura/window_tree_host_unittest.cc
index 6dbddb67770..a2442b8950b 100644
--- a/chromium/ui/aura/window_tree_host_unittest.cc
+++ b/chromium/ui/aura/window_tree_host_unittest.cc
@@ -65,14 +65,8 @@ TEST_F(WindowTreeHostTest, DPIWindowSize) {
host()->SetRootTransform(transform);
EXPECT_EQ(gfx::Rect(0, 1, 534, 401), root_window()->bounds());
- gfx::Insets padding(1, 2, 3, 4);
- // Padding is in physical pixels.
- host()->SetOutputSurfacePaddingInPixels(padding);
- gfx::Rect padded_rect = starting_bounds;
- padded_rect.Inset(-padding);
- EXPECT_EQ(padded_rect.size(), host()->compositor()->size());
EXPECT_EQ(starting_bounds, host()->GetBoundsInPixels());
- EXPECT_EQ(gfx::Rect(1, 1, 534, 401), root_window()->bounds());
+ EXPECT_EQ(gfx::Rect(0, 1, 534, 401), root_window()->bounds());
EXPECT_EQ(gfx::Vector2dF(0, 0),
host()->compositor()->root_layer()->subpixel_position_offset());
}
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
index b5904fe8e63..b209b397877 100644
--- a/chromium/ui/base/BUILD.gn
+++ b/chromium/ui/base/BUILD.gn
@@ -125,8 +125,6 @@ component("base") {
"cocoa/focus_tracker.mm",
"cocoa/focus_window_set.h",
"cocoa/focus_window_set.mm",
- "cocoa/fullscreen_window_manager.h",
- "cocoa/fullscreen_window_manager.mm",
"cocoa/hover_button.h",
"cocoa/hover_button.mm",
"cocoa/hover_image_button.h",
@@ -143,6 +141,8 @@ component("base") {
"cocoa/remote_layer_api.mm",
"cocoa/scoped_cg_context_smooth_fonts.h",
"cocoa/scoped_cg_context_smooth_fonts.mm",
+ "cocoa/secure_password_input.h",
+ "cocoa/secure_password_input.mm",
"cocoa/text_services_context_menu.cc",
"cocoa/text_services_context_menu.h",
"cocoa/three_part_image.h",
@@ -312,9 +312,6 @@ component("base") {
"win/mouse_wheel_util.h",
"win/open_file_name_win.cc",
"win/open_file_name_win.h",
- "win/osk_display_manager.cc",
- "win/osk_display_manager.h",
- "win/osk_display_observer.h",
"win/scoped_ole_initializer.cc",
"win/scoped_ole_initializer.h",
"win/shell.cc",
@@ -731,6 +728,8 @@ static_library("test_support") {
"ime/dummy_input_method.h",
"ime/dummy_text_input_client.cc",
"ime/dummy_text_input_client.h",
+ "ime/win/mock_tsf_bridge.cc",
+ "ime/win/mock_tsf_bridge.h",
]
deps += [
@@ -849,7 +848,6 @@ test("ui_base_unittests") {
"cocoa/controls/hyperlink_button_cell_unittest.mm",
"cocoa/controls/hyperlink_text_view_unittest.mm",
"cocoa/focus_tracker_unittest.mm",
- "cocoa/fullscreen_window_manager_unittest.mm",
"cocoa/hover_button_unittest.mm",
"cocoa/hover_image_button_unittest.mm",
"cocoa/menu_controller_unittest.mm",
@@ -878,7 +876,9 @@ test("ui_base_unittests") {
"ime/input_method_base_unittest.cc",
"ime/input_method_chromeos_unittest.cc",
"ime/win/imm32_manager_unittest.cc",
+ "ime/win/on_screen_keyboard_display_manager_unittest.cc",
"ime/win/tsf_input_scope_unittest.cc",
+ "ime/win/tsf_text_store_unittest.cc",
]
if (is_linux && use_aura && !is_chromeos) {
sources += [ "ime/input_method_auralinux_unittest.cc" ]
@@ -895,7 +895,7 @@ test("ui_base_unittests") {
":ui_base_unittests_bundle_data",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//net",
"//net:test_support",
"//skia",
@@ -928,9 +928,9 @@ test("ui_base_unittests") {
if (is_win) {
sources += [
"dragdrop/os_exchange_data_win_unittest.cc",
+ "win/direct_manipulation_unittest.cc",
"win/hwnd_subclass_unittest.cc",
"win/open_file_name_win_unittest.cc",
- "win/osk_display_manager_unittest.cc",
]
ldflags = [
@@ -1034,6 +1034,8 @@ test("ui_base_unittests") {
if (is_mac) {
mac_framework_bundle("ui_unittests_framework") {
testonly = true
+ framework_version = "U"
+ framework_contents = [ "Resources" ]
deps = [
"//ui/resources:ui_test_pak_bundle_data",
]
diff --git a/chromium/ui/base/accelerators/accelerator.cc b/chromium/ui/base/accelerators/accelerator.cc
index 0694f7433df..a6756c20f22 100644
--- a/chromium/ui/base/accelerators/accelerator.cc
+++ b/chromium/ui/base/accelerators/accelerator.cc
@@ -5,9 +5,11 @@
#include "ui/base/accelerators/accelerator.h"
#include <stdint.h>
+#include <tuple>
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -39,10 +41,12 @@ Accelerator::Accelerator() : Accelerator(VKEY_UNKNOWN, EF_NONE) {}
Accelerator::Accelerator(KeyboardCode key_code,
int modifiers,
- KeyState key_state)
+ KeyState key_state,
+ base::TimeTicks time_stamp)
: key_code_(key_code),
key_state_(key_state),
modifiers_(modifiers & kInterestingFlagsMask),
+ time_stamp_(time_stamp),
interrupted_by_mouse_event_(false) {}
Accelerator::Accelerator(const KeyEvent& key_event)
@@ -51,12 +55,14 @@ Accelerator::Accelerator(const KeyEvent& key_event)
: KeyState::RELEASED),
// |modifiers_| may include the repeat flag.
modifiers_(key_event.flags() & kInterestingFlagsMask),
+ time_stamp_(key_event.time_stamp()),
interrupted_by_mouse_event_(false) {}
Accelerator::Accelerator(const Accelerator& accelerator) {
key_code_ = accelerator.key_code_;
key_state_ = accelerator.key_state_;
modifiers_ = accelerator.modifiers_;
+ time_stamp_ = accelerator.time_stamp_;
interrupted_by_mouse_event_ = accelerator.interrupted_by_mouse_event_;
if (accelerator.platform_accelerator_)
platform_accelerator_ = accelerator.platform_accelerator_->CreateCopy();
@@ -74,7 +80,7 @@ KeyEvent Accelerator::ToKeyEvent() const {
return KeyEvent(key_state() == Accelerator::KeyState::PRESSED
? ET_KEY_PRESSED
: ET_KEY_RELEASED,
- key_code(), modifiers());
+ key_code(), modifiers(), time_stamp());
}
Accelerator& Accelerator::operator=(const Accelerator& accelerator) {
@@ -82,6 +88,7 @@ Accelerator& Accelerator::operator=(const Accelerator& accelerator) {
key_code_ = accelerator.key_code_;
key_state_ = accelerator.key_state_;
modifiers_ = accelerator.modifiers_;
+ time_stamp_ = accelerator.time_stamp_;
interrupted_by_mouse_event_ = accelerator.interrupted_by_mouse_event_;
if (accelerator.platform_accelerator_)
platform_accelerator_ = accelerator.platform_accelerator_->CreateCopy();
@@ -92,14 +99,10 @@ Accelerator& Accelerator::operator=(const Accelerator& accelerator) {
}
bool Accelerator::operator <(const Accelerator& rhs) const {
- if (key_code_ != rhs.key_code_)
- return key_code_ < rhs.key_code_;
- if (key_state_ != rhs.key_state_) {
- return static_cast<int32_t>(key_state_) <
- static_cast<int32_t>(rhs.key_state_);
- }
- return MaskOutKeyEventFlags(modifiers_) <
- MaskOutKeyEventFlags(rhs.modifiers_);
+ const int modifiers_with_mask = MaskOutKeyEventFlags(modifiers_);
+ const int rhs_modifiers_with_mask = MaskOutKeyEventFlags(rhs.modifiers_);
+ return std::tie(key_code_, key_state_, modifiers_with_mask) <
+ std::tie(rhs.key_code_, rhs.key_state_, rhs_modifiers_with_mask);
}
bool Accelerator::operator ==(const Accelerator& rhs) const {
@@ -134,6 +137,170 @@ bool Accelerator::IsRepeat() const {
}
base::string16 Accelerator::GetShortcutText() const {
+ base::string16 shortcut;
+
+#if defined(OS_MACOSX)
+ shortcut = KeyCodeToMacSymbol(key_code_);
+#else
+ shortcut = KeyCodeToName(key_code_);
+#endif
+
+ if (shortcut.empty()) {
+#if defined(OS_WIN)
+ // Our fallback is to try translate the key code to a regular character
+ // unless it is one of digits (VK_0 to VK_9). Some keyboard
+ // layouts have characters other than digits assigned in
+ // an unshifted mode (e.g. French AZERY layout has 'a with grave
+ // accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
+ // default zoom level), we leave VK_[0-9] alone without translation.
+ wchar_t key;
+ if (base::IsAsciiDigit(key_code_))
+ key = static_cast<wchar_t>(key_code_);
+ else
+ key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
+ shortcut += key;
+#elif defined(USE_AURA) || defined(OS_MACOSX)
+ const uint16_t c = DomCodeToUsLayoutCharacter(
+ UsLayoutKeyboardCodeToDomCode(key_code_), false);
+ if (c != 0)
+ shortcut +=
+ static_cast<base::string16::value_type>(base::ToUpperASCII(c));
+#endif
+ }
+
+ // Checking whether the character used for the accelerator is alphanumeric.
+ // If it is not, then we need to adjust the string later on if the locale is
+ // right-to-left. See below for more information of why such adjustment is
+ // required.
+ base::string16 shortcut_rtl;
+ bool adjust_shortcut_for_rtl = false;
+ if (base::i18n::IsRTL() && shortcut.length() == 1 &&
+ !base::IsAsciiAlpha(shortcut[0]) && !base::IsAsciiDigit(shortcut[0])) {
+ adjust_shortcut_for_rtl = true;
+ shortcut_rtl.assign(shortcut);
+ }
+
+#if defined(OS_MACOSX)
+ shortcut = ApplyShortFormModifiers(shortcut);
+#else
+ shortcut = ApplyLongFormModifiers(shortcut);
+#endif
+
+ // For some reason, menus in Windows ignore standard Unicode directionality
+ // marks (such as LRE, PDF, etc.). On RTL locales, we use RTL menus and
+ // therefore any text we draw for the menu items is drawn in an RTL context.
+ // Thus, the text "Ctrl++" (which we currently use for the Zoom In option)
+ // appears as "++Ctrl" in RTL because the Unicode BiDi algorithm puts
+ // punctuations on the left when the context is right-to-left. Shortcuts that
+ // do not end with a punctuation mark (such as "Ctrl+H" do not have this
+ // problem).
+ //
+ // The only way to solve this problem is to adjust the string if the locale
+ // is RTL so that it is drawn correctly in an RTL context. Instead of
+ // returning "Ctrl++" in the above example, we return "++Ctrl". This will
+ // cause the text to appear as "Ctrl++" when Windows draws the string in an
+ // RTL context because the punctuation no longer appears at the end of the
+ // string.
+ //
+ // TODO(idana) bug# 1232732: this hack can be avoided if instead of using
+ // views::Menu we use views::MenuItemView because the latter is a View
+ // subclass and therefore it supports marking text as RTL or LTR using
+ // standard Unicode directionality marks.
+ if (adjust_shortcut_for_rtl) {
+ int key_length = static_cast<int>(shortcut_rtl.length());
+ DCHECK_GT(key_length, 0);
+ shortcut_rtl.append(base::ASCIIToUTF16("+"));
+
+ // Subtracting the size of the shortcut key and 1 for the '+' sign.
+ shortcut_rtl.append(shortcut, 0, shortcut.length() - key_length - 1);
+ shortcut.swap(shortcut_rtl);
+ }
+
+ return shortcut;
+}
+
+base::string16 Accelerator::ApplyLongFormModifiers(
+ base::string16 shortcut) const {
+ if (IsShiftDown())
+ shortcut = l10n_util::GetStringFUTF16(IDS_APP_SHIFT_MODIFIER, shortcut);
+
+ // Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
+ // See http://blogs.msdn.com/oldnewthing/archive/2004/03/29/101121.aspx for
+ // more information.
+ if (IsCtrlDown())
+ shortcut = l10n_util::GetStringFUTF16(IDS_APP_CONTROL_MODIFIER, shortcut);
+ else if (IsAltDown())
+ shortcut = l10n_util::GetStringFUTF16(IDS_APP_ALT_MODIFIER, shortcut);
+
+ if (IsCmdDown()) {
+#if defined(OS_MACOSX)
+ shortcut = l10n_util::GetStringFUTF16(IDS_APP_COMMAND_MODIFIER, shortcut);
+#elif defined(OS_CHROMEOS)
+ shortcut = l10n_util::GetStringFUTF16(IDS_APP_SEARCH_MODIFIER, shortcut);
+#else
+ NOTREACHED();
+#endif
+ }
+
+ return shortcut;
+}
+
+base::string16 Accelerator::ApplyShortFormModifiers(
+ base::string16 shortcut) const {
+ const base::char16 kCommandSymbol[] = {0x2318, 0};
+ const base::char16 kCtrlSymbol[] = {0x2303, 0};
+ const base::char16 kShiftSymbol[] = {0x21e7, 0};
+ const base::char16 kOptionSymbol[] = {0x2325, 0};
+ const base::char16 kNoSymbol[] = {0};
+
+ std::vector<base::string16> parts;
+ parts.push_back(base::string16(IsCtrlDown() ? kCtrlSymbol : kNoSymbol));
+ parts.push_back(base::string16(IsAltDown() ? kOptionSymbol : kNoSymbol));
+ parts.push_back(base::string16(IsShiftDown() ? kShiftSymbol : kNoSymbol));
+ parts.push_back(base::string16(IsCmdDown() ? kCommandSymbol : kNoSymbol));
+ parts.push_back(shortcut);
+ return base::StrCat(parts);
+}
+
+#if defined(OS_MACOSX)
+base::string16 Accelerator::KeyCodeToMacSymbol(KeyboardCode key_code) const {
+ switch (key_code) {
+ case VKEY_CAPITAL:
+ return base::string16({0x21ea, 0});
+ case VKEY_RETURN:
+ return base::string16({0x2324, 0});
+ case VKEY_BACK:
+ return base::string16({0x232b, 0});
+ case VKEY_ESCAPE:
+ return base::string16({0x238b, 0});
+ case VKEY_RIGHT:
+ return base::string16({0x2192, 0});
+ case VKEY_LEFT:
+ return base::string16({0x2190, 0});
+ case VKEY_UP:
+ return base::string16({0x2191, 0});
+ case VKEY_DOWN:
+ return base::string16({0x2193, 0});
+ case VKEY_PRIOR:
+ return base::string16({0x21de, 0});
+ case VKEY_NEXT:
+ return base::string16({0x21df, 0});
+ case VKEY_HOME:
+ return base::string16({0x2196, 0});
+ case VKEY_END:
+ return base::string16({0x2198, 0});
+ case VKEY_TAB:
+ return base::string16({0x21e5, 0});
+ // Mac has a shift-tab icon (0x21e4) but we don't use it.
+ // "Space" and some other keys are written out; fall back to KeyCodeToName()
+ // for those (and any other unhandled keys).
+ default:
+ return KeyCodeToName(key_code);
+ }
+}
+#endif // OS_MACOSX
+
+base::string16 Accelerator::KeyCodeToName(KeyboardCode key_code) const {
int string_id = 0;
switch (key_code_) {
case VKEY_TAB:
@@ -142,9 +309,6 @@ base::string16 Accelerator::GetShortcutText() const {
case VKEY_RETURN:
string_id = IDS_APP_ENTER_KEY;
break;
- case VKEY_ESCAPE:
- string_id = IDS_APP_ESC_KEY;
- break;
case VKEY_SPACE:
string_id = IDS_APP_SPACE_KEY;
break;
@@ -178,6 +342,9 @@ base::string16 Accelerator::GetShortcutText() const {
case VKEY_DOWN:
string_id = IDS_APP_DOWN_ARROW_KEY;
break;
+ case VKEY_ESCAPE:
+ string_id = IDS_APP_ESC_KEY;
+ break;
case VKEY_BACK:
string_id = IDS_APP_BACKSPACE_KEY;
break;
@@ -208,97 +375,7 @@ base::string16 Accelerator::GetShortcutText() const {
default:
break;
}
-
- base::string16 shortcut;
- if (!string_id) {
-#if defined(OS_WIN)
- // Our fallback is to try translate the key code to a regular character
- // unless it is one of digits (VK_0 to VK_9). Some keyboard
- // layouts have characters other than digits assigned in
- // an unshifted mode (e.g. French AZERY layout has 'a with grave
- // accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
- // default zoom level), we leave VK_[0-9] alone without translation.
- wchar_t key;
- if (base::IsAsciiDigit(key_code_))
- key = static_cast<wchar_t>(key_code_);
- else
- key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
- shortcut += key;
-#elif defined(USE_AURA) || defined(OS_MACOSX)
- const uint16_t c = DomCodeToUsLayoutCharacter(
- UsLayoutKeyboardCodeToDomCode(key_code_), false);
- if (c != 0)
- shortcut +=
- static_cast<base::string16::value_type>(base::ToUpperASCII(c));
-#endif
- } else {
- shortcut = l10n_util::GetStringUTF16(string_id);
- }
-
- // Checking whether the character used for the accelerator is alphanumeric.
- // If it is not, then we need to adjust the string later on if the locale is
- // right-to-left. See below for more information of why such adjustment is
- // required.
- base::string16 shortcut_rtl;
- bool adjust_shortcut_for_rtl = false;
- if (base::i18n::IsRTL() && shortcut.length() == 1 &&
- !base::IsAsciiAlpha(shortcut[0]) && !base::IsAsciiDigit(shortcut[0])) {
- adjust_shortcut_for_rtl = true;
- shortcut_rtl.assign(shortcut);
- }
-
- if (IsShiftDown())
- shortcut = l10n_util::GetStringFUTF16(IDS_APP_SHIFT_MODIFIER, shortcut);
-
- // Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
- // See http://blogs.msdn.com/oldnewthing/archive/2004/03/29/101121.aspx for
- // more information.
- if (IsCtrlDown())
- shortcut = l10n_util::GetStringFUTF16(IDS_APP_CONTROL_MODIFIER, shortcut);
- else if (IsAltDown())
- shortcut = l10n_util::GetStringFUTF16(IDS_APP_ALT_MODIFIER, shortcut);
-
- if (IsCmdDown()) {
-#if defined(OS_MACOSX)
- shortcut = l10n_util::GetStringFUTF16(IDS_APP_COMMAND_MODIFIER, shortcut);
-#elif defined(OS_CHROMEOS)
- shortcut = l10n_util::GetStringFUTF16(IDS_APP_SEARCH_MODIFIER, shortcut);
-#else
- NOTREACHED();
-#endif
- }
-
- // For some reason, menus in Windows ignore standard Unicode directionality
- // marks (such as LRE, PDF, etc.). On RTL locales, we use RTL menus and
- // therefore any text we draw for the menu items is drawn in an RTL context.
- // Thus, the text "Ctrl++" (which we currently use for the Zoom In option)
- // appears as "++Ctrl" in RTL because the Unicode BiDi algorithm puts
- // punctuations on the left when the context is right-to-left. Shortcuts that
- // do not end with a punctuation mark (such as "Ctrl+H" do not have this
- // problem).
- //
- // The only way to solve this problem is to adjust the string if the locale
- // is RTL so that it is drawn correctly in an RTL context. Instead of
- // returning "Ctrl++" in the above example, we return "++Ctrl". This will
- // cause the text to appear as "Ctrl++" when Windows draws the string in an
- // RTL context because the punctuation no longer appears at the end of the
- // string.
- //
- // TODO(idana) bug# 1232732: this hack can be avoided if instead of using
- // views::Menu we use views::MenuItemView because the latter is a View
- // subclass and therefore it supports marking text as RTL or LTR using
- // standard Unicode directionality marks.
- if (adjust_shortcut_for_rtl) {
- int key_length = static_cast<int>(shortcut_rtl.length());
- DCHECK_GT(key_length, 0);
- shortcut_rtl.append(base::ASCIIToUTF16("+"));
-
- // Subtracting the size of the shortcut key and 1 for the '+' sign.
- shortcut_rtl.append(shortcut, 0, shortcut.length() - key_length - 1);
- shortcut.swap(shortcut_rtl);
- }
-
- return shortcut;
+ return string_id ? l10n_util::GetStringUTF16(string_id) : base::string16();
}
} // namespace ui
diff --git a/chromium/ui/base/accelerators/accelerator.h b/chromium/ui/base/accelerators/accelerator.h
index e6033bd0830..652aa82d6e4 100644
--- a/chromium/ui/base/accelerators/accelerator.h
+++ b/chromium/ui/base/accelerators/accelerator.h
@@ -15,6 +15,8 @@
#include <utility>
#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
#include "ui/base/accelerators/platform_accelerator.h"
#include "ui/base/ui_base_export.h"
#include "ui/events/event_constants.h"
@@ -44,7 +46,8 @@ class UI_BASE_EXPORT Accelerator {
// NOTE: this constructor strips out non key related flags.
Accelerator(KeyboardCode key_code,
int modifiers,
- KeyState key_state = KeyState::PRESSED);
+ KeyState key_state = KeyState::PRESSED,
+ base::TimeTicks time_stamp = base::TimeTicks());
explicit Accelerator(const KeyEvent& key_event);
Accelerator(const Accelerator& accelerator);
~Accelerator();
@@ -73,6 +76,8 @@ class UI_BASE_EXPORT Accelerator {
int modifiers() const { return modifiers_; }
+ base::TimeTicks time_stamp() const { return time_stamp_; }
+
bool IsShiftDown() const;
bool IsCtrlDown() const;
bool IsAltDown() const;
@@ -100,6 +105,14 @@ class UI_BASE_EXPORT Accelerator {
}
private:
+ base::string16 ApplyLongFormModifiers(base::string16 shortcut) const;
+ base::string16 ApplyShortFormModifiers(base::string16 shortcut) const;
+
+#if defined(OS_MACOSX)
+ base::string16 KeyCodeToMacSymbol(KeyboardCode key_code) const;
+#endif
+ base::string16 KeyCodeToName(KeyboardCode key_code) const;
+
// The keycode (VK_...).
KeyboardCode key_code_;
@@ -108,6 +121,9 @@ class UI_BASE_EXPORT Accelerator {
// The state of the Shift/Ctrl/Alt keys. This corresponds to Event::flags().
int modifiers_;
+ // The |time_stamp_| of the KeyEvent.
+ base::TimeTicks time_stamp_;
+
// Stores platform specific data. May be NULL.
// TODO: this is only used in Mac code and should be removed from here.
// http://crbug.com/702823.
diff --git a/chromium/ui/base/accelerators/accelerator_unittest.cc b/chromium/ui/base/accelerators/accelerator_unittest.cc
index c6ec7b26c53..ad7134c90de 100644
--- a/chromium/ui/base/accelerators/accelerator_unittest.cc
+++ b/chromium/ui/base/accelerators/accelerator_unittest.cc
@@ -4,7 +4,11 @@
#include "ui/base/accelerators/accelerator.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
namespace ui {
@@ -19,4 +23,47 @@ TEST(AcceleratorTest, Repeat) {
EXPECT_TRUE(accelerator_b_copy.IsRepeat());
}
+TEST(AcceleratorTest, TimeStamp) {
+ const Accelerator accelerator_a(VKEY_A, EF_NONE);
+ EXPECT_EQ(base::TimeTicks(), accelerator_a.time_stamp());
+
+ const base::TimeTicks event_time =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(1);
+ KeyEvent keyevent(ET_KEY_PRESSED, VKEY_SPACE, EF_NONE, event_time);
+
+ const Accelerator accelerator_b(keyevent);
+ EXPECT_EQ(event_time, accelerator_b.time_stamp());
+}
+
+#if defined(OS_ANDROID)
+// Keyboard shortcuts don't have meaningful text on Android.
+#define MAYBE_GetShortcutText DISABLED_GetShortcutText
+#else
+#define MAYBE_GetShortcutText GetShortcutText
+#endif
+TEST(AcceleratorTest, MAYBE_GetShortcutText) {
+ struct {
+ KeyboardCode code;
+ int modifiers;
+ const char* expected_long;
+ const char* expected_short;
+ } keys[] = {
+ {VKEY_Q, EF_CONTROL_DOWN | EF_SHIFT_DOWN, "Ctrl+Shift+Q", "\u2303\u21e7Q"},
+ {VKEY_A, EF_ALT_DOWN | EF_SHIFT_DOWN, "Alt+Shift+A", "\u2325\u21e7A"},
+#if defined(OS_MACOSX)
+ {VKEY_T, EF_COMMAND_DOWN | EF_CONTROL_DOWN, nullptr, "\u2303\u2318T"},
+#endif
+ };
+
+ for (const auto& key : keys) {
+ base::string16 text =
+ Accelerator(key.code, key.modifiers).GetShortcutText();
+#if defined(OS_MACOSX)
+ EXPECT_EQ(text, base::UTF8ToUTF16(key.expected_short));
+#else
+ EXPECT_EQ(text, base::UTF8ToUTF16(key.expected_long));
+#endif
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/mojo/BUILD.gn b/chromium/ui/base/accelerators/mojo/BUILD.gn
index 3dd72e7416a..4e028283fc7 100644
--- a/chromium/ui/base/accelerators/mojo/BUILD.gn
+++ b/chromium/ui/base/accelerators/mojo/BUILD.gn
@@ -9,6 +9,7 @@ mojom("interfaces") {
"accelerator.mojom",
]
public_deps = [
+ "//mojo/public/mojom/base",
"//ui/events/mojo:interfaces",
]
}
@@ -19,6 +20,7 @@ source_set("struct_traits") {
]
public_deps = [
":interfaces",
+ "//mojo/public/mojom/base",
"//ui/base",
"//ui/events",
]
diff --git a/chromium/ui/base/accelerators/mojo/DEPS b/chromium/ui/base/accelerators/mojo/DEPS
new file mode 100644
index 00000000000..6cbc2015d05
--- /dev/null
+++ b/chromium/ui/base/accelerators/mojo/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+mojo/common",
+ "+mojo/public/cpp/base",
+]
diff --git a/chromium/ui/base/accelerators/mojo/accelerator.mojom b/chromium/ui/base/accelerators/mojo/accelerator.mojom
index 9bb0329d2f3..77a4029bbe3 100644
--- a/chromium/ui/base/accelerators/mojo/accelerator.mojom
+++ b/chromium/ui/base/accelerators/mojo/accelerator.mojom
@@ -4,6 +4,7 @@
module ui.mojom;
+import "mojo/public/mojom/base/time.mojom";
import "ui/events/mojo/event_constants.mojom";
import "ui/events/mojo/keyboard_codes.mojom";
@@ -20,4 +21,5 @@ struct Accelerator {
int32 key_code;
AcceleratorKeyState key_state;
int32 modifiers;
+ mojo_base.mojom.TimeTicks time_stamp;
};
diff --git a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
index f42de0d797c..c0dc969d7fc 100644
--- a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
+++ b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits.h
@@ -5,6 +5,7 @@
#ifndef UI_BASE_ACCELERATORS_MOJO_ACCELERATOR_STRUCT_TRAITS_H_
#define UI_BASE_ACCELERATORS_MOJO_ACCELERATOR_STRUCT_TRAITS_H_
+#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/mojo/accelerator.mojom.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -49,13 +50,18 @@ struct StructTraits<ui::mojom::AcceleratorDataView, ui::Accelerator> {
return p.key_state();
}
static int32_t modifiers(const ui::Accelerator& p) { return p.modifiers(); }
+ static base::TimeTicks time_stamp(const ui::Accelerator& p) {
+ return p.time_stamp();
+ }
static bool Read(ui::mojom::AcceleratorDataView data, ui::Accelerator* out) {
ui::Accelerator::KeyState key_state;
if (!data.ReadKeyState(&key_state))
return false;
+ base::TimeTicks time_stamp;
+ if (!data.ReadTimeStamp(&time_stamp))
+ return false;
*out = ui::Accelerator(static_cast<ui::KeyboardCode>(data.key_code()),
- data.modifiers());
- out->set_key_state(key_state);
+ data.modifiers(), key_state, time_stamp);
return true;
}
};
diff --git a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits_unittest.cc b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits_unittest.cc
index 24256753a52..08c894fad55 100644
--- a/chromium/ui/base/accelerators/mojo/accelerator_struct_traits_unittest.cc
+++ b/chromium/ui/base/accelerators/mojo/accelerator_struct_traits_unittest.cc
@@ -12,8 +12,10 @@
namespace ui {
TEST(AcceleratorStructTraitsTest, SerializeAndDeserialize1) {
- Accelerator accelerator(KeyboardCode::VKEY_TAB, EF_NUM_LOCK_ON);
- accelerator.set_key_state(ui::Accelerator::KeyState::RELEASED);
+ Accelerator accelerator(
+ KeyboardCode::VKEY_TAB, EF_NUM_LOCK_ON,
+ ui::Accelerator::KeyState::RELEASED,
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(1));
Accelerator deserialized;
ASSERT_TRUE(mojom::Accelerator::Deserialize(
mojom::Accelerator::Serialize(&accelerator), &deserialized));
diff --git a/chromium/ui/base/base_window.h b/chromium/ui/base/base_window.h
index f6af762c130..8d4dd05dfae 100644
--- a/chromium/ui/base/base_window.h
+++ b/chromium/ui/base/base_window.h
@@ -66,6 +66,9 @@ class UI_BASE_EXPORT BaseWindow {
// Hides the window.
virtual void Hide() = 0;
+ // Returns whether the window is visible.
+ virtual bool IsVisible() const = 0;
+
// Show the window, but do not activate it. Does nothing if window
// is already visible.
virtual void ShowInactive() = 0;
diff --git a/chromium/ui/base/class_property_unittest.cc b/chromium/ui/base/class_property_unittest.cc
index 6651c0e79f5..ae9e9019896 100644
--- a/chromium/ui/base/class_property_unittest.cc
+++ b/chromium/ui/base/class_property_unittest.cc
@@ -12,7 +12,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/base/clipboard/clipboard_aurax11.cc b/chromium/ui/base/clipboard/clipboard_aurax11.cc
index 3745f43f580..d071d155a65 100644
--- a/chromium/ui/base/clipboard/clipboard_aurax11.cc
+++ b/chromium/ui/base/clipboard/clipboard_aurax11.cc
@@ -46,7 +46,7 @@ const char kMimeTypeFilename[] = "chromium/filename";
///////////////////////////////////////////////////////////////////////////////
// Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
-class SelectionChangeObserver : public ui::PlatformEventObserver {
+class SelectionChangeObserver : public PlatformEventObserver {
public:
static SelectionChangeObserver* GetInstance();
@@ -61,9 +61,9 @@ class SelectionChangeObserver : public ui::PlatformEventObserver {
SelectionChangeObserver();
~SelectionChangeObserver() override;
- // ui::PlatformEventObserver:
- void WillProcessEvent(const ui::PlatformEvent& event) override;
- void DidProcessEvent(const ui::PlatformEvent& event) override {}
+ // PlatformEventObserver:
+ void WillProcessEvent(const PlatformEvent& event) override;
+ void DidProcessEvent(const PlatformEvent& event) override {}
int event_base_;
Atom clipboard_atom_;
@@ -95,7 +95,7 @@ SelectionChangeObserver::SelectionChangeObserver()
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
- ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+ PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
}
}
@@ -107,7 +107,7 @@ SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
return base::Singleton<SelectionChangeObserver>::get();
}
-void SelectionChangeObserver::WillProcessEvent(const ui::PlatformEvent& event) {
+void SelectionChangeObserver::WillProcessEvent(const PlatformEvent& event) {
if (event->type == event_base_ + XFixesSelectionNotify) {
XFixesSelectionNotifyEvent* ev =
reinterpret_cast<XFixesSelectionNotifyEvent*>(event);
diff --git a/chromium/ui/base/clipboard/clipboard_mac_unittest.mm b/chromium/ui/base/clipboard/clipboard_mac_unittest.mm
index 475db134892..b196332a166 100644
--- a/chromium/ui/base/clipboard/clipboard_mac_unittest.mm
+++ b/chromium/ui/base/clipboard/clipboard_mac_unittest.mm
@@ -58,7 +58,12 @@ class ClipboardMacTest : public PlatformTest {
}
};
-TEST_F(ClipboardMacTest, ReadImageRetina) {
+#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER)
+#define MAYBE_ReadImageRetina DISABLED_ReadImageRetina
+#else
+#define MAYBE_ReadImageRetina ReadImageRetina
+#endif
+TEST_F(ClipboardMacTest, MAYBE_ReadImageRetina) {
int32_t width = 99;
int32_t height = 101;
scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard;
@@ -74,7 +79,12 @@ TEST_F(ClipboardMacTest, ReadImageRetina) {
EXPECT_EQ(2 * height, bitmap.height());
}
-TEST_F(ClipboardMacTest, ReadImageNonRetina) {
+#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER)
+#define MAYBE_ReadImageNonRetina DISABLED_ReadImageNonRetina
+#else
+#define MAYBE_ReadImageNonRetina ReadImageNonRetina
+#endif
+TEST_F(ClipboardMacTest, MAYBE_ReadImageNonRetina) {
int32_t width = 99;
int32_t height = 101;
scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard;
diff --git a/chromium/ui/base/cocoa/fullscreen_window_manager.h b/chromium/ui/base/cocoa/fullscreen_window_manager.h
deleted file mode 100644
index be59cad49c3..00000000000
--- a/chromium/ui/base/cocoa/fullscreen_window_manager.h
+++ /dev/null
@@ -1,40 +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_COCOA_FULLSCREEN_WINDOW_MANAGER_H_
-#define UI_BASE_COCOA_FULLSCREEN_WINDOW_MANAGER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_base_export.h"
-
-// A utility class to manage the fullscreen mode for a given window. This class
-// also updates the window frame if the screen changes.
-UI_BASE_EXPORT
-@interface FullscreenWindowManager : NSObject {
- @private
- base::scoped_nsobject<NSWindow> window_;
- // Explicitly keep track of the screen we want to position the window in.
- // This is better than using -[NSWindow screen] because that might change if
- // the screen changes to a low resolution.
- base::scoped_nsobject<NSScreen> desiredScreen_;
- base::mac::FullScreenMode fullscreenMode_;
- BOOL fullscreenActive_;
-}
-
-- (id)initWithWindow:(NSWindow*)window
- desiredScreen:(NSScreen*)desiredScreen;
-
-// Enables fullscreen mode which causes the menubar and dock to be hidden as
-// needed.
-- (void)enterFullscreenMode;
-
-// Exists fullscreen mode which stops hiding the menubar and dock.
-- (void)exitFullscreenMode;
-
-@end
-
-#endif // UI_BASE_COCOA_FULLSCREEN_WINDOW_MANAGER_H_
diff --git a/chromium/ui/base/cocoa/fullscreen_window_manager.mm b/chromium/ui/base/cocoa/fullscreen_window_manager.mm
deleted file mode 100644
index 15a5948a7b0..00000000000
--- a/chromium/ui/base/cocoa/fullscreen_window_manager.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/base/cocoa/fullscreen_window_manager.h"
-
-namespace {
-
-// Get the screen with the menu bar.
-NSScreen* GetMenuBarScreen() {
- // Documentation in NSScreen says that the first object in
- // +[NSScreen screens] is the menu bar screen.
- NSArray *screens = [NSScreen screens];
- if ([screens count])
- return [screens objectAtIndex:0];
- return nil;
-}
-
-// Get the screen with the dock.
-NSScreen* GetDockScreen() {
- NSArray *screens = [NSScreen screens];
- NSUInteger count = [screens count];
- if (count == 0)
- return NULL;
- if (count == 1)
- return [screens objectAtIndex:0];
-
- for (NSUInteger i = 1; i < count; ++i) {
- NSScreen* screen = [screens objectAtIndex:i];
- // This screen is not the menu bar screen since it's not index 0. Therefore,
- // the only reason that the frame would not match the visible frame is if
- // the dock is on the screen.
- if (!NSEqualRects([screen frame], [screen visibleFrame]))
- return screen;
- }
- return [screens objectAtIndex:0];
-}
-
-} // namespace
-
-@interface FullscreenWindowManager()
-- (void)onScreenChanged:(NSNotification*)note;
-- (void)update;
-@end
-
-@implementation FullscreenWindowManager
-
-- (id)initWithWindow:(NSWindow*)window
- desiredScreen:(NSScreen*)desiredScreen {
- if ((self = [super init])) {
- window_.reset([window retain]);
- desiredScreen_.reset([desiredScreen retain]);
- fullscreenMode_ = base::mac::kFullScreenModeNormal;
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(onScreenChanged:)
- name:NSApplicationDidChangeScreenParametersNotification
- object:NSApp];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self exitFullscreenMode];
- [super dealloc];
-}
-
-- (void)enterFullscreenMode {
- if (fullscreenActive_)
- return;
- fullscreenActive_ = true;
- [self update];
-}
-
-- (void)exitFullscreenMode {
- if (!fullscreenActive_)
- return;
- fullscreenActive_ = false;
- [self update];
-}
-
-- (void)onScreenChanged:(NSNotification*)note {
- [self update];
-}
-
-- (void)update {
- // From OS X 10.10, NSApplicationDidChangeScreenParametersNotification is sent
- // when displaying a fullscreen window, which should normally only be sent if
- // the monitor resolution has changed or new display is detected.
- if (![[NSScreen screens] containsObject:desiredScreen_])
- desiredScreen_.reset([[window_ screen] retain]);
-
- base::mac::FullScreenMode newMode;
- if (!fullscreenActive_)
- newMode = base::mac::kFullScreenModeNormal;
- else if ([desiredScreen_ isEqual:GetMenuBarScreen()])
- newMode = base::mac::kFullScreenModeHideAll;
- else if ([desiredScreen_ isEqual:GetDockScreen()])
- newMode = base::mac::kFullScreenModeHideDock;
- else
- newMode = base::mac::kFullScreenModeNormal;
-
- if (fullscreenMode_ != newMode) {
- if (fullscreenMode_ != base::mac::kFullScreenModeNormal)
- base::mac::ReleaseFullScreen(fullscreenMode_);
- if (newMode != base::mac::kFullScreenModeNormal)
- base::mac::RequestFullScreen(newMode);
- fullscreenMode_ = newMode;
- }
-
- if (fullscreenActive_)
- [window_ setFrame:[desiredScreen_ frame] display:YES];
-}
-
-@end
diff --git a/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm b/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm
deleted file mode 100644
index 25f3dc33280..00000000000
--- a/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/base/cocoa/fullscreen_window_manager.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "ui/base/test/cocoa_helper.h"
-
-typedef ui::CocoaTest FullscreenWindowManagerTest;
-
-TEST_F(FullscreenWindowManagerTest, EnterExit) {
- base::scoped_nsobject<FullscreenWindowManager> manager(
- [[FullscreenWindowManager alloc] initWithWindow:test_window()
- desiredScreen:[NSScreen mainScreen]]);
-
- NSApplicationPresentationOptions current_options =
- [NSApp presentationOptions];
- EXPECT_EQ(NSApplicationPresentationDefault, current_options);
-
- [manager enterFullscreenMode];
- current_options = [NSApp presentationOptions];
- EXPECT_EQ(static_cast<NSApplicationPresentationOptions>(
- NSApplicationPresentationHideDock |
- NSApplicationPresentationHideMenuBar),
- current_options);
-
- [manager exitFullscreenMode];
- current_options = [NSApp presentationOptions];
- EXPECT_EQ(NSApplicationPresentationDefault, current_options);
-}
diff --git a/chromium/ui/base/cocoa/menu_controller.mm b/chromium/ui/base/cocoa/menu_controller.mm
index 384804ab4c9..bf27efe91c6 100644
--- a/chromium/ui/base/cocoa/menu_controller.mm
+++ b/chromium/ui/base/cocoa/menu_controller.mm
@@ -7,7 +7,6 @@
#include "base/cancelable_callback.h"
#include "base/logging.h"
#include "base/mac/bind_objc_block.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/base/accelerators/accelerator.h"
diff --git a/chromium/ui/base/cocoa/secure_password_input.h b/chromium/ui/base/cocoa/secure_password_input.h
new file mode 100644
index 00000000000..ca90d3964a5
--- /dev/null
+++ b/chromium/ui/base/cocoa/secure_password_input.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_COCOA_SECURE_PASSWORD_INPUT_H_
+#define UI_BASE_COCOA_SECURE_PASSWORD_INPUT_H_
+
+#include "base/macros.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// Enables the secure password input mode while in scope.
+class UI_BASE_EXPORT ScopedPasswordInputEnabler {
+ public:
+ ScopedPasswordInputEnabler();
+ ~ScopedPasswordInputEnabler();
+
+ // Returns true if the password input mode is currently enabled. Useful for
+ // unit tests.
+ static bool IsPasswordInputEnabled();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedPasswordInputEnabler);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_COCOA_SECURE_PASSWORD_INPUT_H_
diff --git a/chromium/ui/base/cocoa/secure_password_input.mm b/chromium/ui/base/cocoa/secure_password_input.mm
new file mode 100644
index 00000000000..d0345336d4c
--- /dev/null
+++ b/chromium/ui/base/cocoa/secure_password_input.mm
@@ -0,0 +1,63 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/base/cocoa/secure_password_input.h"
+
+#import <Carbon/Carbon.h>
+
+#include "base/logging.h"
+
+namespace {
+
+// Used to protect from out-of-order calls to enabling/disabling functions.
+int g_password_input_counter = 0;
+
+// SetPasswordInputEnabled() is copied from
+// enableSecureTextInput() and disableSecureTextInput() functions in
+// third_party/WebKit/WebCore/platform/SecureTextInput.cpp
+//
+// The following technote describes proper EnableSecureEventInput() usage:
+// https://developer.apple.com/library/content/technotes/tn2150/_index.html
+void SetPasswordInputEnabled(bool enabled) {
+ if (enabled) {
+ DCHECK(!IsSecureEventInputEnabled());
+ EnableSecureEventInput();
+
+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
+ TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag,
+ sizeof(CFArrayRef), &inputSources);
+ CFRelease(inputSources);
+ } else {
+ DCHECK(IsSecureEventInputEnabled());
+ TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag);
+
+ DisableSecureEventInput();
+ }
+}
+
+} // namespace
+
+namespace ui {
+
+ScopedPasswordInputEnabler::ScopedPasswordInputEnabler() {
+ if (!g_password_input_counter) {
+ SetPasswordInputEnabled(true);
+ }
+ ++g_password_input_counter;
+}
+
+ScopedPasswordInputEnabler::~ScopedPasswordInputEnabler() {
+ --g_password_input_counter;
+ DCHECK_LE(0, g_password_input_counter);
+ if (!g_password_input_counter) {
+ SetPasswordInputEnabled(false);
+ }
+}
+
+// static
+bool ScopedPasswordInputEnabler::IsPasswordInputEnabled() {
+ return g_password_input_counter > 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/text_services_context_menu.cc b/chromium/ui/base/cocoa/text_services_context_menu.cc
index f7cb1dc3c24..e4de9323daf 100644
--- a/chromium/ui/base/cocoa/text_services_context_menu.cc
+++ b/chromium/ui/base/cocoa/text_services_context_menu.cc
@@ -93,11 +93,29 @@ void TextServicesContextMenu::AppendToContextMenu(SimpleMenuModel* model) {
}
void TextServicesContextMenu::AppendEditableItems(SimpleMenuModel* model) {
+ // MacOS provides a contextual menu to set writing direction for BiDi
+ // languages. This functionality is exposed as a keyboard shortcut on
+ // Windows and Linux.
model->AddSubMenuWithStringId(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU,
IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU,
&bidi_submenu_model_);
}
+bool TextServicesContextMenu::SupportsCommand(int command_id) const {
+ switch (command_id) {
+ case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU:
+ case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT:
+ case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR:
+ case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL:
+ case IDS_SPEECH_MAC:
+ case IDS_SPEECH_START_SPEAKING_MAC:
+ case IDS_SPEECH_STOP_SPEAKING_MAC:
+ return true;
+ }
+
+ return false;
+}
+
bool TextServicesContextMenu::IsCommandIdChecked(int command_id) const {
switch (command_id) {
case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT:
@@ -116,6 +134,9 @@ bool TextServicesContextMenu::IsCommandIdChecked(int command_id) const {
bool TextServicesContextMenu::IsCommandIdEnabled(int command_id) const {
switch (command_id) {
+ case IDS_SPEECH_MAC:
+ case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU:
+ return true;
case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT:
case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR:
case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL:
diff --git a/chromium/ui/base/cocoa/text_services_context_menu.h b/chromium/ui/base/cocoa/text_services_context_menu.h
index 2c163d7bee7..e9d48efa68c 100644
--- a/chromium/ui/base/cocoa/text_services_context_menu.h
+++ b/chromium/ui/base/cocoa/text_services_context_menu.h
@@ -15,8 +15,6 @@ namespace ui {
// This class is used to append and handle the Speech and BiDi submenu for the
// context menu.
-// TODO (spqchan): Replace the Speech and BiDi logic in RenderViewContextMenu
-// with TextServicesContextMenu.
class UI_BASE_EXPORT TextServicesContextMenu
: public SimpleMenuModel::Delegate {
public:
@@ -52,6 +50,9 @@ class UI_BASE_EXPORT TextServicesContextMenu
// submenu is added for bidirection, which |this| serves as a delegate for.
void AppendEditableItems(SimpleMenuModel* model);
+ // Returns true if |command_id| is handled by this class.
+ bool SupportsCommand(int command_id) const;
+
// SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.cc b/chromium/ui/base/cursor/cursor_loader_ozone.cc
index ef23518d1e4..b5770539a54 100644
--- a/chromium/ui/base/cursor/cursor_loader_ozone.cc
+++ b/chromium/ui/base/cursor/cursor_loader_ozone.cc
@@ -28,7 +28,7 @@ void CursorLoaderOzone::LoadImageCursor(CursorType id,
GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap);
- cursors_[id] = factory_->CreateImageCursor(bitmap, hotspot, scale());
+ image_cursors_[id] = factory_->CreateImageCursor(bitmap, hotspot, scale());
}
void CursorLoaderOzone::LoadAnimatedCursor(CursorType id,
@@ -41,25 +41,23 @@ void CursorLoaderOzone::LoadAnimatedCursor(CursorType id,
GetAnimatedCursorBitmaps(
resource_id, scale(), rotation(), &hotspot, &bitmaps);
- cursors_[id] =
+ image_cursors_[id] =
factory_->CreateAnimatedCursor(bitmaps, hotspot, frame_delay_ms, scale());
}
void CursorLoaderOzone::UnloadAll() {
- for (ImageCursorMap::const_iterator it = cursors_.begin();
- it != cursors_.end(); ++it) {
- factory_->UnrefImageCursor(it->second);
- }
- cursors_.clear();
+ for (const auto& image_cursor : image_cursors_)
+ factory_->UnrefImageCursor(image_cursor.second);
+ image_cursors_.clear();
}
void CursorLoaderOzone::SetPlatformCursor(gfx::NativeCursor* cursor) {
CursorType native_type = cursor->native_type();
PlatformCursor platform;
- if (cursors_.count(native_type)) {
+ if (image_cursors_.count(native_type)) {
// An image cursor is loaded for this type.
- platform = cursors_[native_type];
+ platform = image_cursors_[native_type];
} else if (native_type == CursorType::kCustom) {
// The platform cursor was already set via WebCursor::GetPlatformCursor.
platform = cursor->platform();
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.h b/chromium/ui/base/cursor/cursor_loader_ozone.h
index acb95717bd5..ea43f0b62fa 100644
--- a/chromium/ui/base/cursor/cursor_loader_ozone.h
+++ b/chromium/ui/base/cursor/cursor_loader_ozone.h
@@ -35,8 +35,7 @@ class UI_BASE_EXPORT CursorLoaderOzone : public CursorLoader {
private:
// Pointers are owned by ResourceBundle and must not be freed here.
- typedef std::map<CursorType, PlatformCursor> ImageCursorMap;
- ImageCursorMap cursors_;
+ std::map<CursorType, PlatformCursor> image_cursors_;
CursorFactoryOzone* factory_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(CursorLoaderOzone);
diff --git a/chromium/ui/base/cursor/cursor_loader_x11.h b/chromium/ui/base/cursor/cursor_loader_x11.h
index e8098fbd104..9fa7beaa272 100644
--- a/chromium/ui/base/cursor/cursor_loader_x11.h
+++ b/chromium/ui/base/cursor/cursor_loader_x11.h
@@ -60,15 +60,12 @@ class UI_BASE_EXPORT CursorLoaderX11 : public CursorLoader {
// A map to hold all image cursors. It maps the cursor ID to the X Cursor, the
// display's scale factor, and the display's rotation.
- typedef std::map<CursorType, std::unique_ptr<ImageCursor>> ImageCursorMap;
- ImageCursorMap image_cursors_;
+ std::map<CursorType, std::unique_ptr<ImageCursor>> image_cursors_;
// A map to hold all animated cursors. It maps the cursor ID to the pair of
// the X Cursor and the corresponding XcursorImages. We need a pointer to the
// images so that we can free them on destruction.
- typedef std::map<CursorType, std::pair<::Cursor, XcursorImages*>>
- AnimatedCursorMap;
- AnimatedCursorMap animated_cursors_;
+ std::map<CursorType, std::pair<::Cursor, XcursorImages*>> animated_cursors_;
const XScopedCursor invisible_cursor_;
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 7a8a2d6fe27..28de403943f 100644
--- a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
+++ b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
@@ -77,9 +77,7 @@ class UI_BASE_EXPORT BitmapCursorFactoryOzone : public CursorFactoryOzone {
scoped_refptr<BitmapCursorOzone> GetDefaultCursorInternal(CursorType type);
// Default cursors are cached & owned by the factory.
- typedef std::map<CursorType, scoped_refptr<BitmapCursorOzone>>
- DefaultCursorMap;
- DefaultCursorMap default_cursors_;
+ std::map<CursorType, scoped_refptr<BitmapCursorOzone>> default_cursors_;
DISALLOW_COPY_AND_ASSIGN(BitmapCursorFactoryOzone);
};
diff --git a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h b/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h
index c9859f23306..b5cba38833a 100644
--- a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h
+++ b/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h
@@ -80,8 +80,7 @@ class UI_BASE_EXPORT CursorDataFactoryOzone : public CursorFactoryOzone {
scoped_refptr<CursorDataOzone> GetDefaultCursorInternal(CursorType type);
// Default cursors are cached & owned by the factory.
- typedef std::map<CursorType, scoped_refptr<CursorDataOzone>> DefaultCursorMap;
- DefaultCursorMap default_cursors_;
+ std::map<CursorType, scoped_refptr<CursorDataOzone>> default_cursors_;
DISALLOW_COPY_AND_ASSIGN(CursorDataFactoryOzone);
};
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
index 6457584efd9..f8e60b31ac6 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
@@ -29,7 +29,7 @@ class OSExchangeDataProviderAuraX11Test;
// OSExchangeData::Provider implementation for aura on linux.
class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
: public OSExchangeData::Provider,
- public ui::PlatformEventDispatcher {
+ public PlatformEventDispatcher {
public:
// |x_window| is the window the cursor is over, and |selection| is the set of
// data being offered.
@@ -91,7 +91,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
gfx::ImageSkia GetDragImage() const override;
gfx::Vector2d GetDragImageOffset() const override;
- // ui::PlatformEventDispatcher:
+ // PlatformEventDispatcher:
bool CanDispatchEvent(const PlatformEvent& event) override;
uint32_t DispatchEvent(const PlatformEvent& event) override;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_builder_mac.mm b/chromium/ui/base/dragdrop/os_exchange_data_provider_builder_mac.mm
index 8eb42de5776..e8d108aa3f0 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_builder_mac.mm
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_builder_mac.mm
@@ -4,7 +4,6 @@
#include "ui/base/dragdrop/os_exchange_data_provider_builder_mac.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/dragdrop/os_exchange_data_provider_mac.h"
namespace ui {
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
index 2837e7984fa..9c3a9ab2cbe 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
@@ -4,7 +4,6 @@
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#if defined(USE_X11)
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 85762b290b1..2aa2920a069 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -18,7 +18,6 @@
#include "base/i18n/file_util_icu.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hdc.h"
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
index 73454128eb9..62d98d1b77a 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
@@ -23,7 +23,7 @@ class OSExchangeDataTest : public PlatformTest {
OSExchangeDataTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
- event_source_(ui::PlatformEventSource::CreateDefault()) {}
+ event_source_(PlatformEventSource::CreateDefault()) {}
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
diff --git a/chromium/ui/base/ime/BUILD.gn b/chromium/ui/base/ime/BUILD.gn
index a8a36ead5f3..9e0c6190234 100644
--- a/chromium/ui/base/ime/BUILD.gn
+++ b/chromium/ui/base/ime/BUILD.gn
@@ -61,8 +61,6 @@ jumbo_component("ime") {
"infolist_entry.cc",
"infolist_entry.h",
"input_method.h",
- "input_method_auralinux.cc",
- "input_method_auralinux.h",
"input_method_base.cc",
"input_method_base.h",
"input_method_chromeos.cc",
@@ -77,8 +75,6 @@ jumbo_component("ime") {
"input_method_minimal.cc",
"input_method_minimal.h",
"input_method_observer.h",
- "input_method_win.cc",
- "input_method_win.h",
"linux/fake_input_method_context.cc",
"linux/fake_input_method_context.h",
"linux/fake_input_method_context_factory.cc",
@@ -96,8 +92,21 @@ jumbo_component("ime") {
"ui_base_ime_export.h",
"win/imm32_manager.cc",
"win/imm32_manager.h",
+ "win/on_screen_keyboard_display_manager_stub.cc",
+ "win/on_screen_keyboard_display_manager_stub.h",
+ "win/on_screen_keyboard_display_manager_tab_tip.cc",
+ "win/on_screen_keyboard_display_manager_tab_tip.h",
+ "win/osk_display_manager.cc",
+ "win/osk_display_manager.h",
+ "win/osk_display_observer.h",
+ "win/tsf_bridge.cc",
+ "win/tsf_bridge.h",
+ "win/tsf_event_router.cc",
+ "win/tsf_event_router.h",
"win/tsf_input_scope.cc",
"win/tsf_input_scope.h",
+ "win/tsf_text_store.cc",
+ "win/tsf_text_store.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -112,6 +121,7 @@ jumbo_component("ime") {
"//net",
"//third_party/icu",
"//ui/base",
+ "//ui/base/ime/chromeos/public/interfaces",
"//ui/display",
"//ui/events",
"//ui/gfx",
@@ -125,8 +135,8 @@ jumbo_component("ime") {
"//skia",
]
- if (!use_aura || is_chromeos || (!is_linux && !use_ozone)) {
- sources -= [
+ if (is_desktop_linux) {
+ sources += [
"input_method_auralinux.cc",
"input_method_auralinux.h",
]
@@ -179,17 +189,25 @@ jumbo_component("ime") {
cflags = [ "/wd4324" ] # Structure was padded due to __declspec(align()), which is
# uninteresting.
+ sources += [
+ "input_method_win.cc",
+ "input_method_win.h",
+ "input_method_win_base.cc",
+ "input_method_win_base.h",
+ "input_method_win_tsf.cc",
+ "input_method_win_tsf.h",
+ ]
libs = [ "imm32.lib" ]
+
+ jumbo_excluded_sources = [
+ # tsf_text_store.cc needs INITGUID to be defined before
+ # including any header to properly generate GUID objects. That
+ # is not guaranteed when included in a jumbo build.
+ "win/tsf_text_store.cc",
+ ]
}
if (is_mac) {
libs = [ "AppKit.framework" ]
}
-
- if (is_fuchsia) {
- sources -= [
- "input_method_auralinux.cc",
- "input_method_auralinux.h",
- ]
- }
}
diff --git a/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn b/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..625cdd4cf3f
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "ime_keyset.mojom",
+ ]
+}
diff --git a/chromium/ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom b/chromium/ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom
new file mode 100644
index 00000000000..7a9d6297a67
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chromeos.input_method.mojom;
+
+// Used by the virtual keyboard to represent different key layouts for
+// different purposes. 'kNone' represents the default key layout.
+// Used in UMA, so this enum should not be reordered.
+enum ImeKeyset {
+ kNone = 0,
+ kEmoji = 1,
+ kHandwriting = 2,
+ kVoice = 3,
+};
diff --git a/chromium/ui/base/ime/composition_text_unittest.cc b/chromium/ui/base/ime/composition_text_unittest.cc
index 8431e2eb6d5..9c57c233388 100644
--- a/chromium/ui/base/ime/composition_text_unittest.cc
+++ b/chromium/ui/base/ime/composition_text_unittest.cc
@@ -14,14 +14,17 @@ namespace ui {
TEST(CompositionTextTest, CopyTest) {
const base::string16 kSampleText = base::UTF8ToUTF16("Sample Text");
const ImeTextSpan kSampleUnderline1(ImeTextSpan::Type::kComposition, 10, 20,
- SK_ColorBLACK, false,
+ ImeTextSpan::Thickness::kThin,
SK_ColorTRANSPARENT);
const ImeTextSpan kSampleUnderline2(ImeTextSpan::Type::kComposition, 11, 21,
- SK_ColorBLACK, true, SK_ColorTRANSPARENT);
+ ImeTextSpan::Thickness::kThick,
+ SK_ColorTRANSPARENT);
- const ImeTextSpan kSampleUnderline3(ImeTextSpan::Type::kComposition, 12, 22,
- SK_ColorRED, false, SK_ColorTRANSPARENT);
+ ImeTextSpan kSampleUnderline3(ImeTextSpan::Type::kComposition, 12, 22,
+ ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT);
+ kSampleUnderline3.underline_color = SK_ColorRED;
// Make CompositionText
CompositionText text;
@@ -43,7 +46,8 @@ TEST(CompositionTextTest, CopyTest) {
text2.ime_text_spans[i].end_offset);
EXPECT_EQ(text.ime_text_spans[i].underline_color,
text2.ime_text_spans[i].underline_color);
- EXPECT_EQ(text.ime_text_spans[i].thick, text2.ime_text_spans[i].thick);
+ EXPECT_EQ(text.ime_text_spans[i].thickness,
+ text2.ime_text_spans[i].thickness);
EXPECT_EQ(text.ime_text_spans[i].background_color,
text2.ime_text_spans[i].background_color);
}
diff --git a/chromium/ui/base/ime/composition_text_util_pango.cc b/chromium/ui/base/ime/composition_text_util_pango.cc
index 9ef58037f7b..e5980f367a0 100644
--- a/chromium/ui/base/ime/composition_text_util_pango.cc
+++ b/chromium/ui/base/ime/composition_text_util_pango.cc
@@ -74,15 +74,16 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
if (background_attr || underline_attr) {
- // Use a black thin underline by default.
+ // Use a thin underline with text color by default.
ImeTextSpan ime_text_span(ImeTextSpan::Type::kComposition,
char16_offsets[start], char16_offsets[end],
- SK_ColorBLACK, false, SK_ColorTRANSPARENT);
+ ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT);
// Always use thick underline for a range with background color, which
// is usually the selection range.
if (background_attr) {
- ime_text_span.thick = true;
+ ime_text_span.thickness = ImeTextSpan::Thickness::kThick;
// If the cursor is at start or end of this underline, then we treat
// it as the selection range as well, but make sure to set the cursor
// position to the selection end.
@@ -97,7 +98,7 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
if (underline_attr) {
int type = reinterpret_cast<PangoAttrInt*>(underline_attr)->value;
if (type == PANGO_UNDERLINE_DOUBLE)
- ime_text_span.thick = true;
+ ime_text_span.thickness = ImeTextSpan::Thickness::kThick;
else if (type == PANGO_UNDERLINE_ERROR)
ime_text_span.underline_color = SK_ColorRED;
}
@@ -107,11 +108,11 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
pango_attr_iterator_destroy(iter);
}
- // Use a black thin underline by default.
+ // Use a thin underline with text color by default.
if (composition->ime_text_spans.empty()) {
composition->ime_text_spans.push_back(
- ImeTextSpan(ImeTextSpan::Type::kComposition, 0, length, SK_ColorBLACK,
- false, SK_ColorTRANSPARENT));
+ ImeTextSpan(ImeTextSpan::Type::kComposition, 0, length,
+ ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
}
}
diff --git a/chromium/ui/base/ime/composition_text_util_pango_unittest.cc b/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
index be674433b65..26e34395208 100644
--- a/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
+++ b/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
@@ -29,7 +29,7 @@ struct ImeTextSpan {
unsigned start_offset;
unsigned end_offset;
uint32_t underline_color;
- bool thick;
+ ui::ImeTextSpan::Thickness thickness;
uint32_t background_color;
};
@@ -47,10 +47,13 @@ const TestData kTestData[] = {
{PANGO_ATTR_BACKGROUND, 0, 4, 7},
{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13},
{0, 0, 0, 0}},
- {{0, 3, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {4, 7, SK_ColorBLACK, true, SK_ColorTRANSPARENT},
- {8, 13, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {0, 0, 0, false, SK_ColorTRANSPARENT}}},
+ {{0, 3, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {4, 7, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThick,
+ SK_ColorTRANSPARENT},
+ {8, 13, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {0, 0, 0, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT}}},
// Offset overflow.
{"One Two Three",
@@ -58,10 +61,13 @@ const TestData kTestData[] = {
{PANGO_ATTR_BACKGROUND, 0, 4, 7},
{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 20},
{0, 0, 0, 0}},
- {{0, 3, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {4, 7, SK_ColorBLACK, true, SK_ColorTRANSPARENT},
- {8, 13, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {0, 0, 0, false, SK_ColorTRANSPARENT}}},
+ {{0, 3, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {4, 7, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThick,
+ SK_ColorTRANSPARENT},
+ {8, 13, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {0, 0, 0, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT}}},
// Error underline.
{"One Two Three",
@@ -69,16 +75,20 @@ const TestData kTestData[] = {
{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_ERROR, 4, 7},
{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13},
{0, 0, 0, 0}},
- {{0, 3, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {4, 7, SK_ColorRED, false, SK_ColorTRANSPARENT},
- {8, 13, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {0, 0, 0, false, SK_ColorTRANSPARENT}}},
+ {{0, 3, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {4, 7, SK_ColorRED, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {8, 13, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {0, 0, 0, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT}}},
// Default underline.
{"One Two Three",
{{0, 0, 0, 0}},
- {{0, 13, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {0, 0, 0, false, SK_ColorTRANSPARENT}}},
+ {{0, 13, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {0, 0, 0, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT}}},
// Unicode, including non-BMP characters: "123你好𠀀𠀁一丁 456"
{"123\xE4\xBD\xA0\xE5\xA5\xBD\xF0\xA0\x80\x80\xF0\xA0\x80\x81\xE4\xB8\x80"
@@ -88,18 +98,22 @@ const TestData kTestData[] = {
{PANGO_ATTR_BACKGROUND, 0, 5, 7},
{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 7, 13},
{0, 0, 0, 0}},
- {{0, 3, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {3, 5, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {5, 9, SK_ColorBLACK, true, SK_ColorTRANSPARENT},
- {9, 15, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
- {0, 0, 0, false, SK_ColorTRANSPARENT}}},
+ {{0, 3, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {3, 5, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {5, 9, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThick,
+ SK_ColorTRANSPARENT},
+ {9, 15, SK_ColorTRANSPARENT, ui::ImeTextSpan::Thickness::kThin,
+ SK_ColorTRANSPARENT},
+ {0, 0, 0, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT}}},
};
void CompareImeTextSpan(const ImeTextSpan& a, const ui::ImeTextSpan& b) {
EXPECT_EQ(a.start_offset, b.start_offset);
EXPECT_EQ(a.end_offset, b.end_offset);
EXPECT_EQ(a.underline_color, b.underline_color);
- EXPECT_EQ(a.thick, b.thick);
+ EXPECT_EQ(a.thickness, b.thickness);
EXPECT_EQ(a.background_color, b.background_color);
}
diff --git a/chromium/ui/base/ime/dummy_input_method.cc b/chromium/ui/base/ime/dummy_input_method.cc
index 9b6b2cdf89b..cda3ff2221e 100644
--- a/chromium/ui/base/ime/dummy_input_method.cc
+++ b/chromium/ui/base/ime/dummy_input_method.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ui/base/ime/dummy_input_method.h"
+#include "build/build_config.h"
#include "ui/events/event.h"
namespace ui {
@@ -22,10 +23,12 @@ void DummyInputMethod::OnFocus() {
void DummyInputMethod::OnBlur() {
}
-bool DummyInputMethod::OnUntranslatedIMEMessage(const base::NativeEvent& event,
+#if defined(OS_WIN)
+bool DummyInputMethod::OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) {
return false;
}
+#endif
void DummyInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
}
diff --git a/chromium/ui/base/ime/dummy_input_method.h b/chromium/ui/base/ime/dummy_input_method.h
index 6a9201f484f..8b41021b831 100644
--- a/chromium/ui/base/ime/dummy_input_method.h
+++ b/chromium/ui/base/ime/dummy_input_method.h
@@ -6,6 +6,7 @@
#define UI_BASE_IME_DUMMY_INPUT_METHOD_H_
#include "base/macros.h"
+#include "build/build_config.h"
#include "ui/base/ime/input_method.h"
namespace ui {
@@ -21,8 +22,12 @@ class DummyInputMethod : public InputMethod {
void SetDelegate(internal::InputMethodDelegate* delegate) override;
void OnFocus() override;
void OnBlur() override;
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+
+#if defined(OS_WIN)
+ bool OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) override;
+#endif
+
void SetFocusedTextInputClient(TextInputClient* client) override;
void DetachTextInputClient(TextInputClient* client) override;
TextInputClient* GetTextInputClient() const override;
diff --git a/chromium/ui/base/ime/ime_engine_handler_interface.h b/chromium/ui/base/ime/ime_engine_handler_interface.h
index 3987085386a..a226fa38b6e 100644
--- a/chromium/ui/base/ime/ime_engine_handler_interface.h
+++ b/chromium/ui/base/ime/ime_engine_handler_interface.h
@@ -28,7 +28,7 @@ class KeyEvent;
// A interface to handle the engine handler method call.
class UI_BASE_IME_EXPORT IMEEngineHandlerInterface {
public:
- typedef base::Callback<void(bool consumed)> KeyEventDoneCallback;
+ typedef base::OnceCallback<void(bool consumed)> KeyEventDoneCallback;
// A information about a focused text input field.
// A type of each member is based on the html spec, but InputContext can be
@@ -74,7 +74,7 @@ class UI_BASE_IME_EXPORT IMEEngineHandlerInterface {
// Called when the key event is received.
// Actual implementation must call |callback| after key event handling.
virtual void ProcessKeyEvent(const KeyEvent& key_event,
- KeyEventDoneCallback& callback) = 0;
+ KeyEventDoneCallback callback) = 0;
// Called when a new surrounding text is set. The |text| is surrounding text
// and |cursor_pos| is 0 based index of cursor position in |text|. If there is
diff --git a/chromium/ui/base/ime/ime_text_span.cc b/chromium/ui/base/ime/ime_text_span.cc
index 1ee2876be35..14b482ed591 100644
--- a/chromium/ui/base/ime/ime_text_span.cc
+++ b/chromium/ui/base/ime/ime_text_span.cc
@@ -9,32 +9,28 @@
namespace ui {
-ImeTextSpan::ImeTextSpan() : ImeTextSpan(0, 0, SK_ColorTRANSPARENT, false) {}
+ImeTextSpan::ImeTextSpan() : ImeTextSpan(0, 0, Thickness::kThin) {}
ImeTextSpan::ImeTextSpan(uint32_t start_offset,
uint32_t end_offset,
- SkColor underline_color,
- bool thick)
+ Thickness thickness)
: ImeTextSpan(Type::kComposition,
start_offset,
end_offset,
- underline_color,
- thick,
+ thickness,
SK_ColorTRANSPARENT) {}
ImeTextSpan::ImeTextSpan(Type type,
uint32_t start_offset,
uint32_t end_offset,
- SkColor underline_color,
- bool thick,
+ Thickness thickness,
SkColor background_color,
SkColor suggestion_highlight_color,
const std::vector<std::string>& suggestions)
: type(type),
start_offset(start_offset),
end_offset(end_offset),
- underline_color(underline_color),
- thick(thick),
+ thickness(thickness),
background_color(background_color),
suggestion_highlight_color(suggestion_highlight_color),
suggestions(suggestions) {}
diff --git a/chromium/ui/base/ime/ime_text_span.h b/chromium/ui/base/ime/ime_text_span.h
index eee554f4fe2..e47064a1a63 100644
--- a/chromium/ui/base/ime/ime_text_span.h
+++ b/chromium/ui/base/ime/ime_text_span.h
@@ -31,19 +31,23 @@ struct UI_BASE_IME_EXPORT ImeTextSpan {
kMisspellingSuggestion,
};
+ enum class Thickness {
+ kNone,
+ kThin,
+ kThick,
+ };
+
// The default constructor is used by generated Mojo code.
ImeTextSpan();
// TODO(huangs): remove this constructor.
ImeTextSpan(uint32_t start_offset,
uint32_t end_offset,
- SkColor underline_color,
- bool thick);
+ Thickness thickness);
ImeTextSpan(
Type type,
uint32_t start_offset,
uint32_t end_offset,
- SkColor underline_color,
- bool thick,
+ Thickness thickness,
SkColor background_color,
SkColor suggestion_highlight_color = SK_ColorTRANSPARENT,
const std::vector<std::string>& suggestions = std::vector<std::string>());
@@ -57,7 +61,7 @@ struct UI_BASE_IME_EXPORT ImeTextSpan {
(this->start_offset == rhs.start_offset) &&
(this->end_offset == rhs.end_offset) &&
(this->underline_color == rhs.underline_color) &&
- (this->thick == rhs.thick) &&
+ (this->thickness == rhs.thickness) &&
(this->background_color == rhs.background_color) &&
(this->suggestion_highlight_color ==
rhs.suggestion_highlight_color) &&
@@ -69,8 +73,8 @@ struct UI_BASE_IME_EXPORT ImeTextSpan {
Type type;
uint32_t start_offset;
uint32_t end_offset;
- SkColor underline_color;
- bool thick;
+ SkColor underline_color = SK_ColorTRANSPARENT;
+ Thickness thickness;
SkColor background_color;
SkColor suggestion_highlight_color;
std::vector<std::string> suggestions;
diff --git a/chromium/ui/base/ime/input_method.h b/chromium/ui/base/ime/input_method.h
index fad2ecca3bb..1a5fb7adbd7 100644
--- a/chromium/ui/base/ime/input_method.h
+++ b/chromium/ui/base/ime/input_method.h
@@ -11,11 +11,11 @@
#include <string>
#include <vector>
-#include "base/event_types.h"
#include "build/build_config.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/events/event_dispatcher.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/geometry/rect.h"
namespace extensions {
@@ -76,12 +76,13 @@ class InputMethod {
// Called when the top-level system window loses keyboard focus.
virtual void OnBlur() = 0;
+#if defined(OS_WIN)
// Called when the focused window receives native IME messages that are not
// translated into other predefined event callbacks. Currently this method is
// used only for IME functionalities specific to Windows.
- // TODO(ime): Break down these messages into platform-neutral methods.
- virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ virtual bool OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) = 0;
+#endif
// Sets the text input client which receives text input events such as
// SetCompositionText(). |client| can be NULL. A gfx::NativeWindow which
diff --git a/chromium/ui/base/ime/input_method_auralinux.cc b/chromium/ui/base/ime/input_method_auralinux.cc
index 9a6c7bee4fc..c02def8d3f7 100644
--- a/chromium/ui/base/ime/input_method_auralinux.cc
+++ b/chromium/ui/base/ime/input_method_auralinux.cc
@@ -46,12 +46,6 @@ LinuxInputMethodContext* InputMethodAuraLinux::GetContextForTesting(
// Overriden from InputMethod.
-bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
- const base::NativeEvent& event,
- NativeEventResult* result) {
- return false;
-}
-
ui::EventDispatchDetails InputMethodAuraLinux::DispatchKeyEvent(
ui::KeyEvent* event) {
DCHECK(event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED);
@@ -99,13 +93,14 @@ ui::EventDispatchDetails InputMethodAuraLinux::DispatchKeyEvent(
if (text_input_type_ != TEXT_INPUT_TYPE_PASSWORD &&
GetEngine() && GetEngine()->IsInterestedInKeyEvent() &&
(!filtered || NeedInsertChar())) {
- ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback = base::Bind(
- &InputMethodAuraLinux::ProcessKeyEventByEngineDone,
- weak_ptr_factory_.GetWeakPtr(), base::Owned(new ui::KeyEvent(*event)),
- filtered, composition_changed_,
- base::Owned(new ui::CompositionText(composition_)),
- base::Owned(new base::string16(result_text_)));
- GetEngine()->ProcessKeyEvent(*event, callback);
+ ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
+ base::BindOnce(&InputMethodAuraLinux::ProcessKeyEventByEngineDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(new ui::KeyEvent(*event)), filtered,
+ composition_changed_,
+ base::Owned(new ui::CompositionText(composition_)),
+ base::Owned(new base::string16(result_text_)));
+ GetEngine()->ProcessKeyEvent(*event, std::move(callback));
return ui::EventDispatchDetails();
}
diff --git a/chromium/ui/base/ime/input_method_auralinux.h b/chromium/ui/base/ime/input_method_auralinux.h
index 7a2adae8cf4..ef4985b95c6 100644
--- a/chromium/ui/base/ime/input_method_auralinux.h
+++ b/chromium/ui/base/ime/input_method_auralinux.h
@@ -27,8 +27,6 @@ class UI_BASE_IME_EXPORT InputMethodAuraLinux
LinuxInputMethodContext* GetContextForTesting(bool is_simple);
// Overriden from InputMethod.
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnTextInputTypeChanged(const TextInputClient* client) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc
index 7d4747b5c05..ea0e64490e5 100644
--- a/chromium/ui/base/ime/input_method_base.cc
+++ b/chromium/ui/base/ime/input_method_base.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/input_method_observer.h"
@@ -22,9 +23,9 @@ ui::IMEEngineHandlerInterface* InputMethodBase::GetEngine() {
return nullptr;
}
-InputMethodBase::InputMethodBase()
+InputMethodBase::InputMethodBase(internal::InputMethodDelegate* delegate)
: sending_key_event_(false),
- delegate_(nullptr),
+ delegate_(delegate),
text_input_client_(nullptr) {}
InputMethodBase::~InputMethodBase() {
@@ -53,6 +54,14 @@ void InputMethodBase::OnBlur() {
ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
}
+#if defined(OS_WIN)
+bool InputMethodBase::OnUntranslatedIMEMessage(
+ const MSG event,
+ InputMethod::NativeEventResult* result) {
+ return false;
+}
+#endif
+
void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) {
SetFocusedTextInputClientInternal(client);
}
@@ -143,17 +152,17 @@ ui::EventDispatchDetails InputMethodBase::DispatchKeyEventPostIME(
ui::EventDispatchDetails InputMethodBase::DispatchKeyEventPostIME(
ui::KeyEvent* event,
- std::unique_ptr<base::OnceCallback<void(bool)>> ack_callback) const {
+ base::OnceCallback<void(bool)> ack_callback) const {
if (delegate_) {
ui::EventDispatchDetails details =
delegate_->DispatchKeyEventPostIME(event);
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(event->stopped_propagation());
+ if (ack_callback)
+ std::move(ack_callback).Run(event->stopped_propagation());
return details;
}
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
return EventDispatchDetails();
}
diff --git a/chromium/ui/base/ime/input_method_base.h b/chromium/ui/base/ime/input_method_base.h
index 6a26900d342..f97938b4213 100644
--- a/chromium/ui/base/ime/input_method_base.h
+++ b/chromium/ui/base/ime/input_method_base.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "build/build_config.h"
#include "ui/base/ime/ime_input_context_handler_interface.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/ui_base_ime_export.h"
@@ -34,13 +35,19 @@ class UI_BASE_IME_EXPORT InputMethodBase
public base::SupportsWeakPtr<InputMethodBase>,
public IMEInputContextHandlerInterface {
public:
- InputMethodBase();
+ explicit InputMethodBase(internal::InputMethodDelegate* delegate = nullptr);
~InputMethodBase() override;
// Overriden from InputMethod.
void SetDelegate(internal::InputMethodDelegate* delegate) override;
void OnFocus() override;
void OnBlur() override;
+
+#if defined(OS_WIN)
+ bool OnUntranslatedIMEMessage(const MSG event,
+ NativeEventResult* result) override;
+#endif
+
void SetFocusedTextInputClient(TextInputClient* client) override;
void DetachTextInputClient(TextInputClient* client) override;
TextInputClient* GetTextInputClient() const override;
@@ -100,8 +107,7 @@ class UI_BASE_IME_EXPORT InputMethodBase
virtual ui::EventDispatchDetails DispatchKeyEventPostIME(
ui::KeyEvent* event,
- std::unique_ptr<base::OnceCallback<void(bool)>> ack_callback) const
- WARN_UNUSED_RESULT;
+ base::OnceCallback<void(bool)> ack_callback) const WARN_UNUSED_RESULT;
// Convenience method to notify all observers of TextInputClient changes.
void NotifyTextInputStateChanged(const TextInputClient* client);
diff --git a/chromium/ui/base/ime/input_method_base_unittest.cc b/chromium/ui/base/ime/input_method_base_unittest.cc
index cccce2d70f5..d5f7dd8936a 100644
--- a/chromium/ui/base/ime/input_method_base_unittest.cc
+++ b/chromium/ui/base/ime/input_method_base_unittest.cc
@@ -140,11 +140,6 @@ class MockInputMethodBase : public InputMethodBase {
private:
// Overriden from InputMethod.
- bool OnUntranslatedIMEMessage(
- const base::NativeEvent& event,
- InputMethod::NativeEventResult* result) override {
- return false;
- }
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent*) override {
return ui::EventDispatchDetails();
}
diff --git a/chromium/ui/base/ime/input_method_chromeos.cc b/chromium/ui/base/ime/input_method_chromeos.cc
index fba861cd4a9..b11f08eaad0 100644
--- a/chromium/ui/base/ime/input_method_chromeos.cc
+++ b/chromium/ui/base/ime/input_method_chromeos.cc
@@ -15,7 +15,6 @@
#include "base/bind.h"
#include "base/i18n/char_iterator.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
@@ -105,8 +104,7 @@ ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent(
// TODO(shuchen): Eventually, the language input keys should be handed
// over to the IME extension to process. And IMF can handle if the IME
// extension didn't handle.
- return DispatchKeyEventPostIME(
- event, std::make_unique<AckCallback>(std::move(ack_callback)));
+ return DispatchKeyEventPostIME(event, std::move(ack_callback));
}
}
}
@@ -121,36 +119,28 @@ ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent(
if (ExecuteCharacterComposer(*event)) {
// Treating as PostIME event if character composer handles key event and
// generates some IME event,
- return ProcessKeyEventPostIME(
- event, std::make_unique<AckCallback>(std::move(ack_callback)),
- false, true);
+ return ProcessKeyEventPostIME(event, std::move(ack_callback), false,
+ true);
}
- return ProcessUnfilteredKeyPressEvent(
- event, std::make_unique<AckCallback>(std::move(ack_callback)));
+ return ProcessUnfilteredKeyPressEvent(event, std::move(ack_callback));
}
- return DispatchKeyEventPostIME(
- event, std::make_unique<AckCallback>(std::move(ack_callback)));
+ return DispatchKeyEventPostIME(event, std::move(ack_callback));
}
handling_key_event_ = true;
if (GetEngine()->IsInterestedInKeyEvent()) {
- ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback = base::Bind(
- &InputMethodChromeOS::KeyEventDoneCallback,
- weak_ptr_factory_.GetWeakPtr(),
- // Pass the ownership of the new copied event.
- base::Owned(new ui::KeyEvent(*event)), Passed(&ack_callback));
- GetEngine()->ProcessKeyEvent(*event, callback);
+ ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
+ base::BindOnce(&InputMethodChromeOS::KeyEventDoneCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ // Pass the ownership of the new copied event.
+ base::Owned(new ui::KeyEvent(*event)),
+ std::move(ack_callback));
+ GetEngine()->ProcessKeyEvent(*event, std::move(callback));
return ui::EventDispatchDetails();
}
return ProcessKeyEventDone(event, std::move(ack_callback), false);
}
-bool InputMethodChromeOS::OnUntranslatedIMEMessage(
- const base::NativeEvent& event,
- NativeEventResult* result) {
- return false;
-}
-
void InputMethodChromeOS::KeyEventDoneCallback(ui::KeyEvent* event,
AckCallback ack_callback,
bool is_handled) {
@@ -176,9 +166,8 @@ ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventDone(
}
ui::EventDispatchDetails details;
if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) {
- details = ProcessKeyEventPostIME(
- event, std::make_unique<AckCallback>(std::move(ack_callback)), false,
- is_handled);
+ details = ProcessKeyEventPostIME(event, std::move(ack_callback), false,
+ is_handled);
}
handling_key_event_ = false;
return details;
@@ -361,7 +350,7 @@ void InputMethodChromeOS::UpdateContextFocusState() {
ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback,
+ AckCallback ack_callback,
bool skip_process_filtered,
bool handled) {
TextInputClient* client = GetTextInputClient();
@@ -378,8 +367,8 @@ ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
// In case the focus was changed by the key event. The |context_| should have
// been reset when the focused window changed.
if (client != GetTextInputClient()) {
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
return dispatch_details;
}
if (HasInputMethodResult())
@@ -388,14 +377,14 @@ ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
// In case the focus was changed when sending input method results to the
// focused window.
if (client != GetTextInputClient()) {
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
return dispatch_details;
}
if (handled) {
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(true);
+ if (ack_callback)
+ std::move(ack_callback).Run(true);
return dispatch_details; // IME handled the key event. do not forward.
}
@@ -409,11 +398,11 @@ ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
ui::EventDispatchDetails InputMethodChromeOS::ProcessFilteredKeyPressEvent(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback) {
- auto callback = std::make_unique<AckCallback>(base::Bind(
+ AckCallback ack_callback) {
+ auto callback = base::Bind(
&InputMethodChromeOS::PostProcessFilteredKeyPressEvent,
weak_ptr_factory_.GetWeakPtr(), base::Owned(new ui::KeyEvent(*event)),
- GetTextInputClient(), Passed(&ack_callback)));
+ GetTextInputClient(), Passed(&ack_callback));
if (NeedInsertChar())
return DispatchKeyEventPostIME(event, std::move(callback));
@@ -434,7 +423,7 @@ ui::EventDispatchDetails InputMethodChromeOS::ProcessFilteredKeyPressEvent(
void InputMethodChromeOS::PostProcessFilteredKeyPressEvent(
ui::KeyEvent* event,
TextInputClient* prev_client,
- std::unique_ptr<AckCallback> ack_callback,
+ AckCallback ack_callback,
bool stopped_propagation) {
// In case the focus was changed by the key event.
if (GetTextInputClient() != prev_client)
@@ -442,8 +431,8 @@ void InputMethodChromeOS::PostProcessFilteredKeyPressEvent(
if (stopped_propagation) {
ResetContext();
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(true);
+ if (ack_callback)
+ std::move(ack_callback).Run(true);
return;
}
ignore_result(
@@ -452,24 +441,24 @@ void InputMethodChromeOS::PostProcessFilteredKeyPressEvent(
ui::EventDispatchDetails InputMethodChromeOS::ProcessUnfilteredKeyPressEvent(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback) {
+ AckCallback ack_callback) {
return DispatchKeyEventPostIME(
event,
- std::make_unique<AckCallback>(base::Bind(
- &InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent,
- weak_ptr_factory_.GetWeakPtr(), base::Owned(new ui::KeyEvent(*event)),
- GetTextInputClient(), Passed(&ack_callback))));
+ base::BindOnce(&InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(new ui::KeyEvent(*event)),
+ GetTextInputClient(), std::move(ack_callback)));
}
void InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent(
ui::KeyEvent* event,
TextInputClient* prev_client,
- std::unique_ptr<AckCallback> ack_callback,
+ AckCallback ack_callback,
bool stopped_propagation) {
if (stopped_propagation) {
ResetContext();
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
return;
}
@@ -482,8 +471,8 @@ void InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent(
// We should return here not to send the Tab key event to RWHV.
TextInputClient* client = GetTextInputClient();
if (!client || client != prev_client) {
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
return;
}
@@ -494,8 +483,8 @@ void InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent(
if (ch)
client->InsertChar(*event);
- if (ack_callback && !ack_callback->is_null())
- std::move(*ack_callback).Run(false);
+ if (ack_callback)
+ std::move(ack_callback).Run(false);
}
void InputMethodChromeOS::ProcessInputMethodResult(ui::KeyEvent* event,
@@ -703,9 +692,9 @@ void InputMethodChromeOS::ExtractCompositionText(
continue;
ImeTextSpan ime_text_span(ui::ImeTextSpan::Type::kComposition,
char16_offsets[start], char16_offsets[end],
- text_ime_text_spans[i].underline_color,
- text_ime_text_spans[i].thick,
+ text_ime_text_spans[i].thickness,
text_ime_text_spans[i].background_color);
+ ime_text_span.underline_color = text_ime_text_spans[i].underline_color;
out_composition->ime_text_spans.push_back(ime_text_span);
}
}
@@ -716,7 +705,7 @@ void InputMethodChromeOS::ExtractCompositionText(
const uint32_t end = text.selection.end();
ImeTextSpan ime_text_span(ui::ImeTextSpan::Type::kComposition,
char16_offsets[start], char16_offsets[end],
- SK_ColorBLACK, true /* thick */,
+ ui::ImeTextSpan::Thickness::kThick,
SK_ColorTRANSPARENT);
out_composition->ime_text_spans.push_back(ime_text_span);
@@ -732,11 +721,11 @@ void InputMethodChromeOS::ExtractCompositionText(
}
}
- // Use a black thin underline by default.
+ // Use a thin underline with text color by default.
if (out_composition->ime_text_spans.empty()) {
out_composition->ime_text_spans.push_back(
ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, length,
- SK_ColorBLACK, false /* thick */, SK_ColorTRANSPARENT));
+ ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
}
}
diff --git a/chromium/ui/base/ime/input_method_chromeos.h b/chromium/ui/base/ime/input_method_chromeos.h
index 24859210c03..c86e65c66a4 100644
--- a/chromium/ui/base/ime/input_method_chromeos.h
+++ b/chromium/ui/base/ime/input_method_chromeos.h
@@ -33,8 +33,6 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
AckCallback ack_callback);
// Overridden from InputMethod:
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnTextInputTypeChanged(const TextInputClient* client) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
@@ -50,7 +48,7 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
// Process a key returned from the input method.
virtual ui::EventDispatchDetails ProcessKeyEventPostIME(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback,
+ AckCallback ack_callback,
bool skip_process_filtered,
bool handled) WARN_UNUSED_RESULT;
@@ -79,26 +77,24 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
// when dispatching post IME.
ui::EventDispatchDetails ProcessFilteredKeyPressEvent(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback) WARN_UNUSED_RESULT;
+ AckCallback ack_callback) WARN_UNUSED_RESULT;
// Post processes a key event that was already filtered by the input method.
- void PostProcessFilteredKeyPressEvent(
- ui::KeyEvent* event,
- TextInputClient* prev_client,
- std::unique_ptr<AckCallback> ack_callback,
- bool stopped_propagation);
+ void PostProcessFilteredKeyPressEvent(ui::KeyEvent* event,
+ TextInputClient* prev_client,
+ AckCallback ack_callback,
+ bool stopped_propagation);
// Processes a key event that was not filtered by the input method.
ui::EventDispatchDetails ProcessUnfilteredKeyPressEvent(
ui::KeyEvent* event,
- std::unique_ptr<AckCallback> ack_callback) WARN_UNUSED_RESULT;
+ AckCallback ack_callback) WARN_UNUSED_RESULT;
// Post processes a key event that was unfiltered by the input method.
- void PostProcessUnfilteredKeyPressEvent(
- ui::KeyEvent* event,
- TextInputClient* prev_client,
- std::unique_ptr<AckCallback> ack_callback,
- bool stopped_propagation);
+ void PostProcessUnfilteredKeyPressEvent(ui::KeyEvent* event,
+ TextInputClient* prev_client,
+ AckCallback ack_callback,
+ bool stopped_propagation);
// Sends input method result caused by the given key event to the focused text
// input client.
diff --git a/chromium/ui/base/ime/input_method_chromeos_unittest.cc b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
index fc127d28125..c826c1f150e 100644
--- a/chromium/ui/base/ime/input_method_chromeos_unittest.cc
+++ b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
@@ -51,11 +51,6 @@ uint32_t GetOffsetInUTF16(const base::string16& utf16_string,
return char_iterator.array_pos();
}
-enum KeyEventHandlerBehavior {
- KEYEVENT_CONSUME,
- KEYEVENT_NOT_CONSUME,
-};
-
} // namespace
@@ -67,22 +62,23 @@ class TestableInputMethodChromeOS : public InputMethodChromeOS {
}
struct ProcessKeyEventPostIMEArgs {
- ProcessKeyEventPostIMEArgs() : event(NULL), handled(false) {}
- const ui::KeyEvent* event;
+ ProcessKeyEventPostIMEArgs()
+ : event(ET_UNKNOWN, VKEY_UNKNOWN, DomCode::NONE, EF_NONE),
+ handled(false) {}
+ ui::KeyEvent event;
bool handled;
};
// Overridden from InputMethodChromeOS:
- ui::EventDispatchDetails ProcessKeyEventPostIME(
- ui::KeyEvent* key_event,
- std::unique_ptr<AckCallback> ack_callback,
- bool skip_process_filtered,
- bool handled) override {
+ ui::EventDispatchDetails ProcessKeyEventPostIME(ui::KeyEvent* key_event,
+ AckCallback ack_callback,
+ bool skip_process_filtered,
+ bool handled) override {
ui::EventDispatchDetails details =
InputMethodChromeOS::ProcessKeyEventPostIME(
key_event, std::move(ack_callback), skip_process_filtered, handled);
if (!skip_process_filtered) {
- process_key_event_post_ime_args_.event = key_event;
+ process_key_event_post_ime_args_.event = *key_event;
process_key_event_post_ime_args_.handled = handled;
++process_key_event_post_ime_call_count_;
}
@@ -110,72 +106,6 @@ class TestableInputMethodChromeOS : public InputMethodChromeOS {
int process_key_event_post_ime_call_count_;
};
-class SynchronousKeyEventHandler {
- public:
- SynchronousKeyEventHandler(uint32_t expected_keyval,
- uint32_t expected_keycode,
- uint32_t expected_state,
- KeyEventHandlerBehavior behavior)
- : expected_keyval_(expected_keyval),
- expected_keycode_(expected_keycode),
- expected_state_(expected_state),
- behavior_(behavior) {}
-
- virtual ~SynchronousKeyEventHandler() {}
-
- void Run(uint32_t keyval,
- uint32_t keycode,
- uint32_t state,
- const KeyEventCallback& callback) {
- EXPECT_EQ(expected_keyval_, keyval);
- EXPECT_EQ(expected_keycode_, keycode);
- EXPECT_EQ(expected_state_, state);
- callback.Run(behavior_ == KEYEVENT_CONSUME);
- }
-
- private:
- const uint32_t expected_keyval_;
- const uint32_t expected_keycode_;
- const uint32_t expected_state_;
- const KeyEventHandlerBehavior behavior_;
-
- DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler);
-};
-
-class AsynchronousKeyEventHandler {
- public:
- AsynchronousKeyEventHandler(uint32_t expected_keyval,
- uint32_t expected_keycode,
- uint32_t expected_state)
- : expected_keyval_(expected_keyval),
- expected_keycode_(expected_keycode),
- expected_state_(expected_state) {}
-
- virtual ~AsynchronousKeyEventHandler() {}
-
- void Run(uint32_t keyval,
- uint32_t keycode,
- uint32_t state,
- const KeyEventCallback& callback) {
- EXPECT_EQ(expected_keyval_, keyval);
- EXPECT_EQ(expected_keycode_, keycode);
- EXPECT_EQ(expected_state_, state);
- callback_ = callback;
- }
-
- void RunCallback(KeyEventHandlerBehavior behavior) {
- callback_.Run(behavior == KEYEVENT_CONSUME);
- }
-
- private:
- const uint32_t expected_keyval_;
- const uint32_t expected_keycode_;
- const uint32_t expected_state_;
- KeyEventCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler);
-};
-
class SetSurroundingTextVerifier {
public:
SetSurroundingTextVerifier(const std::string& expected_surrounding_text,
@@ -605,7 +535,8 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_NoAttribute) {
EXPECT_EQ(0UL, composition_text.ime_text_spans[0].start_offset);
EXPECT_EQ(kSampleAsciiText.size(),
composition_text.ime_text_spans[0].end_offset);
- EXPECT_FALSE(composition_text.ime_text_spans[0].thick);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThin,
+ composition_text.ime_text_spans[0].thickness);
}
TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) {
@@ -615,7 +546,7 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) {
CompositionText composition_text;
composition_text.text = kSampleText;
ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL,
- SK_ColorBLACK, false, SK_ColorTRANSPARENT);
+ ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT);
composition_text.ime_text_spans.push_back(underline);
CompositionText composition_text2;
@@ -630,9 +561,11 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) {
composition_text2.ime_text_spans[0].start_offset);
EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_offset),
composition_text2.ime_text_spans[0].end_offset);
- // Single underline represents as black thin line.
- EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_FALSE(composition_text2.ime_text_spans[0].thick);
+ // Single underline represents as thin line with text color.
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition_text2.ime_text_spans[0].underline_color);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThin,
+ composition_text2.ime_text_spans[0].thickness);
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
composition_text2.ime_text_spans[0].background_color);
}
@@ -644,7 +577,8 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) {
CompositionText composition_text;
composition_text.text = kSampleText;
ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL,
- SK_ColorBLACK, true, SK_ColorTRANSPARENT);
+ ui::ImeTextSpan::Thickness::kThick,
+ SK_ColorTRANSPARENT);
composition_text.ime_text_spans.push_back(underline);
CompositionText composition_text2;
@@ -659,9 +593,11 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) {
composition_text2.ime_text_spans[0].start_offset);
EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_offset),
composition_text2.ime_text_spans[0].end_offset);
- // Double underline represents as black thick line.
- EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_TRUE(composition_text2.ime_text_spans[0].thick);
+ // Double underline represents as thick line with text color.
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition_text2.ime_text_spans[0].underline_color);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThick,
+ composition_text2.ime_text_spans[0].thickness);
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
composition_text2.ime_text_spans[0].background_color);
}
@@ -672,8 +608,9 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) {
// Set up chromeos composition text with one underline attribute.
CompositionText composition_text;
composition_text.text = kSampleText;
- ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL, SK_ColorRED,
- false, SK_ColorTRANSPARENT);
+ ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL,
+ ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT);
+ underline.underline_color = SK_ColorRED;
composition_text.ime_text_spans.push_back(underline);
CompositionText composition_text2;
@@ -689,7 +626,8 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) {
composition_text2.ime_text_spans[0].end_offset);
// Error underline represents as red thin line.
EXPECT_EQ(SK_ColorRED, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_FALSE(composition_text2.ime_text_spans[0].thick);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThin,
+ composition_text2.ime_text_spans[0].thickness);
}
TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) {
@@ -712,8 +650,10 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) {
composition_text2.ime_text_spans[0].start_offset);
EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()),
composition_text2.ime_text_spans[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_TRUE(composition_text2.ime_text_spans[0].thick);
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition_text2.ime_text_spans[0].underline_color);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThick,
+ composition_text2.ime_text_spans[0].thickness);
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
composition_text2.ime_text_spans[0].background_color);
}
@@ -743,8 +683,10 @@ TEST_F(InputMethodChromeOSTest,
composition_text2.ime_text_spans[0].start_offset);
EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()),
composition_text2.ime_text_spans[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_TRUE(composition_text2.ime_text_spans[0].thick);
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition_text2.ime_text_spans[0].underline_color);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThick,
+ composition_text2.ime_text_spans[0].thickness);
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
composition_text2.ime_text_spans[0].background_color);
}
@@ -774,8 +716,10 @@ TEST_F(InputMethodChromeOSTest,
composition_text2.ime_text_spans[0].start_offset);
EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()),
composition_text2.ime_text_spans[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color);
- EXPECT_TRUE(composition_text2.ime_text_spans[0].thick);
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition_text2.ime_text_spans[0].underline_color);
+ EXPECT_EQ(ui::ImeTextSpan::Thickness::kThick,
+ composition_text2.ime_text_spans[0].thickness);
EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
composition_text2.ime_text_spans[0].background_color);
}
@@ -913,14 +857,14 @@ TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseTest) {
EXPECT_EQ(0, inserted_char_);
// Do callback.
- mock_ime_engine_handler_->last_passed_callback().Run(true);
+ std::move(mock_ime_engine_handler_->last_passed_callback()).Run(true);
// Check the results
EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count());
- const ui::KeyEvent* stored_event =
+ const ui::KeyEvent stored_event =
ime_->process_key_event_post_ime_args().event;
- EXPECT_EQ(ui::VKEY_A, stored_event->key_code());
- EXPECT_EQ(kFlags, stored_event->flags());
+ EXPECT_EQ(ui::VKEY_A, stored_event.key_code());
+ EXPECT_EQ(kFlags, stored_event.flags());
EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
EXPECT_EQ(L'A', inserted_char_);
@@ -966,16 +910,15 @@ TEST_F(InputMethodChromeOSKeyEventTest, MultiKeyEventDelayResponseTest) {
EXPECT_EQ(0, composition_text_.text[0]);
// Do callback for first key event.
- first_callback.Run(true);
+ std::move(first_callback).Run(true);
EXPECT_EQ(comp.text, composition_text_.text);
// Check the results for first key event.
EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count());
- const ui::KeyEvent* stored_event =
- ime_->process_key_event_post_ime_args().event;
- EXPECT_EQ(ui::VKEY_B, stored_event->key_code());
- EXPECT_EQ(kFlags, stored_event->flags());
+ ui::KeyEvent stored_event = ime_->process_key_event_post_ime_args().event;
+ EXPECT_EQ(ui::VKEY_B, stored_event.key_code());
+ EXPECT_EQ(kFlags, stored_event.flags());
EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
EXPECT_EQ(0, inserted_char_);
@@ -985,8 +928,8 @@ TEST_F(InputMethodChromeOSKeyEventTest, MultiKeyEventDelayResponseTest) {
// Check the results for second key event.
EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count());
stored_event = ime_->process_key_event_post_ime_args().event;
- EXPECT_EQ(ui::VKEY_C, stored_event->key_code());
- EXPECT_EQ(kFlags, stored_event->flags());
+ EXPECT_EQ(ui::VKEY_C, stored_event.key_code());
+ EXPECT_EQ(kFlags, stored_event.flags());
EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled);
EXPECT_EQ(L'C', inserted_char_);
@@ -1030,7 +973,8 @@ TEST_F(InputMethodChromeOSKeyEventTest, DeadKeyPressTest) {
0,
DomKey::DeadKeyFromCombiningCharacter('^'),
EventTimeForNow());
- ime_->ProcessKeyEventPostIME(&eventA, nullptr, false, true);
+ ime_->ProcessKeyEventPostIME(&eventA, InputMethodChromeOS::AckCallback(),
+ false, true);
const ui::KeyEvent& key_event = dispatched_key_event_;
diff --git a/chromium/ui/base/ime/input_method_factory.cc b/chromium/ui/base/ime/input_method_factory.cc
index a1b1798fba6..d93dd27f82f 100644
--- a/chromium/ui/base/ime/input_method_factory.cc
+++ b/chromium/ui/base/ime/input_method_factory.cc
@@ -8,12 +8,14 @@
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/base/ime/mock_input_method.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/switches.h"
#if defined(OS_CHROMEOS)
#include "ui/base/ime/input_method_chromeos.h"
#elif defined(OS_WIN)
#include "ui/base/ime/input_method_win.h"
+#include "ui/base/ime/input_method_win_tsf.h"
#elif defined(OS_MACOSX)
#include "ui/base/ime/input_method_mac.h"
#elif defined(USE_AURA) && defined(USE_X11)
@@ -55,6 +57,8 @@ std::unique_ptr<InputMethod> CreateInputMethod(
#if defined(OS_CHROMEOS)
return std::make_unique<InputMethodChromeOS>(delegate);
#elif defined(OS_WIN)
+ if (base::FeatureList::IsEnabled(features::kTSFImeSupport))
+ return std::make_unique<InputMethodWinTSF>(delegate, widget);
return std::make_unique<InputMethodWin>(delegate, widget);
#elif defined(OS_MACOSX)
return std::make_unique<InputMethodMac>(delegate);
diff --git a/chromium/ui/base/ime/input_method_initializer.cc b/chromium/ui/base/ime/input_method_initializer.cc
index 026b564b502..b64f362a5d8 100644
--- a/chromium/ui/base/ime/input_method_initializer.cc
+++ b/chromium/ui/base/ime/input_method_initializer.cc
@@ -11,6 +11,9 @@
#elif defined(USE_AURA) && defined(OS_LINUX)
#include "base/logging.h"
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
+#elif defined(OS_WIN)
+#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/ime/win/tsf_bridge.h"
#endif
namespace {
@@ -27,12 +30,16 @@ namespace ui {
void InitializeInputMethod() {
#if defined(OS_CHROMEOS)
IMEBridge::Initialize();
+#elif defined(OS_WIN)
+ TSFBridge::Initialize();
#endif
}
void ShutdownInputMethod() {
#if defined(OS_CHROMEOS)
IMEBridge::Shutdown();
+#elif defined(OS_WIN)
+ TSFBridge::Shutdown();
#endif
}
@@ -50,6 +57,10 @@ void InitializeInputMethodForTesting() {
<< "else.";
LinuxInputMethodContextFactory::SetInstance(
g_linux_input_method_context_factory_for_testing);
+#elif defined(OS_WIN)
+ // Make sure COM is initialized because TSF depends on COM.
+ CoInitialize(nullptr);
+ TSFBridge::Initialize();
#endif
}
@@ -64,6 +75,9 @@ void ShutdownInputMethodForTesting() {
LinuxInputMethodContextFactory::SetInstance(NULL);
delete g_linux_input_method_context_factory_for_testing;
g_linux_input_method_context_factory_for_testing = NULL;
+#elif defined(OS_WIN)
+ TSFBridge::Shutdown();
+ CoUninitialize();
#endif
}
diff --git a/chromium/ui/base/ime/input_method_mac.h b/chromium/ui/base/ime/input_method_mac.h
index 25d371881e0..7ca676d113a 100644
--- a/chromium/ui/base/ime/input_method_mac.h
+++ b/chromium/ui/base/ime/input_method_mac.h
@@ -20,8 +20,6 @@ class UI_BASE_IME_EXPORT InputMethodMac : public InputMethodBase {
~InputMethodMac() override;
// Overriden from InputMethod.
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
void CancelComposition(const TextInputClient* client) override;
diff --git a/chromium/ui/base/ime/input_method_mac.mm b/chromium/ui/base/ime/input_method_mac.mm
index d048773109c..1b4e953d7c0 100644
--- a/chromium/ui/base/ime/input_method_mac.mm
+++ b/chromium/ui/base/ime/input_method_mac.mm
@@ -15,11 +15,6 @@ InputMethodMac::InputMethodMac(internal::InputMethodDelegate* delegate) {
InputMethodMac::~InputMethodMac() {
}
-bool InputMethodMac::OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) {
- return false;
-}
-
ui::EventDispatchDetails InputMethodMac::DispatchKeyEvent(ui::KeyEvent* event) {
// This is used on Mac only to dispatch events post-IME.
return DispatchKeyEventPostIME(event);
diff --git a/chromium/ui/base/ime/input_method_minimal.cc b/chromium/ui/base/ime/input_method_minimal.cc
index d040d9fd415..331fc8e9cf9 100644
--- a/chromium/ui/base/ime/input_method_minimal.cc
+++ b/chromium/ui/base/ime/input_method_minimal.cc
@@ -19,12 +19,6 @@ InputMethodMinimal::InputMethodMinimal(
InputMethodMinimal::~InputMethodMinimal() {}
-bool InputMethodMinimal::OnUntranslatedIMEMessage(
- const base::NativeEvent& event,
- NativeEventResult* result) {
- return false;
-}
-
ui::EventDispatchDetails InputMethodMinimal::DispatchKeyEvent(
ui::KeyEvent* event) {
DCHECK(event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED);
diff --git a/chromium/ui/base/ime/input_method_minimal.h b/chromium/ui/base/ime/input_method_minimal.h
index 96359226adc..259c9993529 100644
--- a/chromium/ui/base/ime/input_method_minimal.h
+++ b/chromium/ui/base/ime/input_method_minimal.h
@@ -18,8 +18,6 @@ class UI_BASE_IME_EXPORT InputMethodMinimal : public InputMethodBase {
~InputMethodMinimal() override;
// Overriden from InputMethod.
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
void CancelComposition(const TextInputClient* client) override;
diff --git a/chromium/ui/base/ime/input_method_win.cc b/chromium/ui/base/ime/input_method_win.cc
index 06f8831222d..4c3b458047e 100644
--- a/chromium/ui/base/ime/input_method_win.cc
+++ b/chromium/ui/base/ime/input_method_win.cc
@@ -25,10 +25,6 @@
namespace ui {
namespace {
-// Extra number of chars before and after selection (or composition) range which
-// is returned to IME for improving conversion accuracy.
-static const size_t kExtraNumberOfChars = 20;
-
ui::EventDispatchDetails DispatcherDestroyedDetails() {
ui::EventDispatchDetails dispatcher_details;
dispatcher_details.dispatcher_destroyed = true;
@@ -39,14 +35,12 @@ ui::EventDispatchDetails DispatcherDestroyedDetails() {
InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
HWND toplevel_window_handle)
- : toplevel_window_handle_(toplevel_window_handle),
+ : InputMethodWinBase(delegate, toplevel_window_handle),
pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION),
- accept_carriage_return_(false),
enabled_(false),
is_candidate_popup_open_(false),
composing_window_handle_(NULL),
weak_ptr_factory_(this) {
- SetDelegate(delegate);
imm32_manager_.SetInputLanguage();
}
@@ -58,7 +52,7 @@ void InputMethodWin::OnFocus() {
}
bool InputMethodWin::OnUntranslatedIMEMessage(
- const base::NativeEvent& event,
+ const MSG event,
InputMethod::NativeEventResult* result) {
LRESULT original_result = 0;
BOOL handled = FALSE;
@@ -106,7 +100,7 @@ ui::EventDispatchDetails InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) {
if (!event->HasNativeEvent())
return DispatchFabricatedKeyEvent(event);
- const base::NativeEvent& native_key_event = event->native_event();
+ const PlatformEvent& native_key_event = event->native_event();
BOOL handled = FALSE;
if (native_key_event.message == WM_CHAR) {
auto ref = weak_ptr_factory_.GetWeakPtr();
@@ -178,11 +172,12 @@ ui::EventDispatchDetails InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) {
// messages have been combined in the event processing flow.
if (char_msgs.size() <= 1 && GetEngine() &&
GetEngine()->IsInterestedInKeyEvent()) {
- ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback = base::Bind(
- &InputMethodWin::ProcessKeyEventDone, weak_ptr_factory_.GetWeakPtr(),
- base::Owned(new ui::KeyEvent(*event)),
- base::Owned(new std::vector<MSG>(char_msgs)));
- GetEngine()->ProcessKeyEvent(*event, callback);
+ ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
+ base::BindOnce(&InputMethodWin::ProcessKeyEventDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(new ui::KeyEvent(*event)),
+ base::Owned(new std::vector<MSG>(char_msgs)));
+ GetEngine()->ProcessKeyEvent(*event, std::move(callback));
return ui::EventDispatchDetails();
}
@@ -313,44 +308,7 @@ void InputMethodWin::OnDidChangeFocusedClient(
// bounds has not changed.
OnCaretBoundsChanged(focused);
}
- if (focused_before != focused)
- accept_carriage_return_ = false;
-}
-
-LRESULT InputMethodWin::OnChar(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- const base::NativeEvent& event,
- BOOL* handled) {
- *handled = TRUE;
-
- // We need to send character events to the focused text input client event if
- // its text input type is ui::TEXT_INPUT_TYPE_NONE.
- if (GetTextInputClient()) {
- const base::char16 kCarriageReturn = L'\r';
- const base::char16 ch = static_cast<base::char16>(wparam);
- // A mask to determine the previous key state from |lparam|. The value is 1
- // if the key is down before the message is sent, or it is 0 if the key is
- // up.
- const uint32_t kPrevKeyDownBit = 0x40000000;
- if (ch == kCarriageReturn && !(lparam & kPrevKeyDownBit))
- accept_carriage_return_ = true;
- // Conditionally ignore '\r' events to work around crbug.com/319100.
- // TODO(yukawa, IME): Figure out long-term solution.
- if (ch != kCarriageReturn || accept_carriage_return_) {
- ui::KeyEvent char_event(event);
- GetTextInputClient()->InsertChar(char_event);
- }
- }
-
- // Explicitly show the system menu at a good location on [Alt]+[Space].
- // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system
- // menu causes undesirable titlebar artifacts in the classic theme.
- if (message == WM_SYSCHAR && wparam == VK_SPACE)
- gfx::ShowSystemMenu(window_handle);
-
- return 0;
+ InputMethodWinBase::OnDidChangeFocusedClient(focused_before, focused);
}
LRESULT InputMethodWin::OnImeSetContext(HWND window_handle,
@@ -481,188 +439,6 @@ LRESULT InputMethodWin::OnImeNotify(UINT message,
return 0;
}
-LRESULT InputMethodWin::OnImeRequest(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- *handled = FALSE;
-
- // Should not receive WM_IME_REQUEST message, if IME is disabled.
- const ui::TextInputType type = GetTextInputType();
- if (type == ui::TEXT_INPUT_TYPE_NONE ||
- type == ui::TEXT_INPUT_TYPE_PASSWORD) {
- return 0;
- }
-
- switch (wparam) {
- case IMR_RECONVERTSTRING:
- *handled = TRUE;
- return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
- case IMR_DOCUMENTFEED:
- *handled = TRUE;
- return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
- case IMR_QUERYCHARPOSITION:
- *handled = TRUE;
- return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
- default:
- return 0;
- }
-}
-
-LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
- ui::TextInputClient* client = GetTextInputClient();
- if (!client)
- return 0;
-
- gfx::Range text_range;
- if (!client->GetTextRange(&text_range) || text_range.is_empty())
- return 0;
-
- bool result = false;
- gfx::Range target_range;
- if (client->HasCompositionText())
- result = client->GetCompositionTextRange(&target_range);
-
- if (!result || target_range.is_empty()) {
- if (!client->GetSelectionRange(&target_range) ||
- !target_range.IsValid()) {
- return 0;
- }
- }
-
- if (!text_range.Contains(target_range))
- return 0;
-
- if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars)
- text_range.set_start(target_range.GetMin() - kExtraNumberOfChars);
-
- if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars)
- text_range.set_end(target_range.GetMax() + kExtraNumberOfChars);
-
- size_t len = text_range.length();
- size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
-
- if (!reconv)
- return need_size;
-
- if (reconv->dwSize < need_size)
- return 0;
-
- base::string16 text;
- if (!GetTextInputClient()->GetTextFromRange(text_range, &text))
- return 0;
- DCHECK_EQ(text_range.length(), text.length());
-
- reconv->dwVersion = 0;
- reconv->dwStrLen = len;
- reconv->dwStrOffset = sizeof(RECONVERTSTRING);
- reconv->dwCompStrLen =
- client->HasCompositionText() ? target_range.length() : 0;
- reconv->dwCompStrOffset =
- (target_range.GetMin() - text_range.start()) * sizeof(WCHAR);
- reconv->dwTargetStrLen = target_range.length();
- reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
-
- memcpy((char*)reconv + sizeof(RECONVERTSTRING),
- text.c_str(), len * sizeof(WCHAR));
-
- // According to Microsoft API document, IMR_RECONVERTSTRING and
- // IMR_DOCUMENTFEED should return reconv, but some applications return
- // need_size.
- return reinterpret_cast<LRESULT>(reconv);
-}
-
-LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) {
- ui::TextInputClient* client = GetTextInputClient();
- if (!client)
- return 0;
-
- // If there is a composition string already, we don't allow reconversion.
- if (client->HasCompositionText())
- return 0;
-
- gfx::Range text_range;
- if (!client->GetTextRange(&text_range) || text_range.is_empty())
- return 0;
-
- gfx::Range selection_range;
- if (!client->GetSelectionRange(&selection_range) ||
- selection_range.is_empty()) {
- return 0;
- }
-
- DCHECK(text_range.Contains(selection_range));
-
- size_t len = selection_range.length();
- size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
-
- if (!reconv)
- return need_size;
-
- if (reconv->dwSize < need_size)
- return 0;
-
- // TODO(penghuang): Return some extra context to help improve IME's
- // reconversion accuracy.
- base::string16 text;
- if (!GetTextInputClient()->GetTextFromRange(selection_range, &text))
- return 0;
- DCHECK_EQ(selection_range.length(), text.length());
-
- reconv->dwVersion = 0;
- reconv->dwStrLen = len;
- reconv->dwStrOffset = sizeof(RECONVERTSTRING);
- reconv->dwCompStrLen = len;
- reconv->dwCompStrOffset = 0;
- reconv->dwTargetStrLen = len;
- reconv->dwTargetStrOffset = 0;
-
- memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
- text.c_str(), len * sizeof(WCHAR));
-
- // According to Microsoft API document, IMR_RECONVERTSTRING and
- // IMR_DOCUMENTFEED should return reconv, but some applications return
- // need_size.
- return reinterpret_cast<LRESULT>(reconv);
-}
-
-LRESULT InputMethodWin::OnQueryCharPosition(IMECHARPOSITION* char_positon) {
- if (!char_positon)
- return 0;
-
- if (char_positon->dwSize < sizeof(IMECHARPOSITION))
- return 0;
-
- ui::TextInputClient* client = GetTextInputClient();
- if (!client)
- return 0;
-
- // Tentatively assume that the returned value from |client| is DIP (Density
- // Independent Pixel). See the comment in text_input_client.h and
- // http://crbug.com/360334.
- gfx::Rect dip_rect;
- if (client->HasCompositionText()) {
- if (!client->GetCompositionCharacterBounds(char_positon->dwCharPos,
- &dip_rect)) {
- return 0;
- }
- } else {
- // If there is no composition and the first character is queried, returns
- // the caret bounds. This behavior is the same to that of RichEdit control.
- if (char_positon->dwCharPos != 0)
- return 0;
- dip_rect = client->GetCaretBounds();
- }
- const gfx::Rect rect =
- display::win::ScreenWin::DIPToScreenRect(toplevel_window_handle_,
- dip_rect);
-
- char_positon->pt.x = rect.x();
- char_positon->pt.y = rect.y();
- char_positon->cLineHeight = rect.height();
- return 1; // returns non-zero value when succeeded.
-}
-
void InputMethodWin::RefreshInputLanguage() {
TextInputType type_original = GetTextInputType();
imm32_manager_.SetInputLanguage();
@@ -677,18 +453,6 @@ void InputMethodWin::RefreshInputLanguage() {
}
}
-bool InputMethodWin::IsWindowFocused(const TextInputClient* client) const {
- if (!client)
- return false;
- // When Aura is enabled, |attached_window_handle| should always be a top-level
- // window. So we can safely assume that |attached_window_handle| is ready for
- // receiving keyboard input as long as it is an active window. This works well
- // even when the |attached_window_handle| becomes active but has not received
- // WM_FOCUS yet.
- return toplevel_window_handle_ &&
- GetActiveWindow() == toplevel_window_handle_;
-}
-
ui::EventDispatchDetails InputMethodWin::DispatchFabricatedKeyEvent(
ui::KeyEvent* event) {
// The key event if from calling input.ime.sendKeyEvent or test.
diff --git a/chromium/ui/base/ime/input_method_win.h b/chromium/ui/base/ime/input_method_win.h
index c41504e29ff..603c456fb16 100644
--- a/chromium/ui/base/ime/input_method_win.h
+++ b/chromium/ui/base/ime/input_method_win.h
@@ -11,13 +11,13 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "ui/base/ime/input_method_base.h"
+#include "ui/base/ime/input_method_win_base.h"
#include "ui/base/ime/win/imm32_manager.h"
namespace ui {
// A common InputMethod implementation based on IMM32.
-class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodBase {
+class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodWinBase {
public:
InputMethodWin(internal::InputMethodDelegate* delegate,
HWND toplevel_window_handle);
@@ -27,7 +27,7 @@ class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodBase {
void OnFocus() override;
// Overridden from InputMethod:
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ bool OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnTextInputTypeChanged(const TextInputClient* client) override;
@@ -47,14 +47,6 @@ class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodBase {
TextInputClient* focused) override;
private:
- // For both WM_CHAR and WM_SYSCHAR
- LRESULT OnChar(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- const base::NativeEvent& event,
- BOOL* handled);
-
LRESULT OnImeSetContext(HWND window_handle,
UINT message,
WPARAM wparam,
@@ -80,23 +72,8 @@ class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodBase {
LPARAM lparam,
BOOL* handled);
- // Some IMEs rely on WM_IME_REQUEST message even when TSF is enabled. So
- // OnImeRequest (and its actual implementations as OnDocumentFeed,
- // OnReconvertString, and OnQueryCharPosition) are placed in this base class.
- LRESULT OnImeRequest(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
- LRESULT OnDocumentFeed(RECONVERTSTRING* reconv);
- LRESULT OnReconvertString(RECONVERTSTRING* reconv);
- LRESULT OnQueryCharPosition(IMECHARPOSITION* char_positon);
-
void RefreshInputLanguage();
- // Returns true if the Win32 native window bound to |client| is considered
- // to be ready for receiving keyboard input.
- bool IsWindowFocused(const TextInputClient* client) const;
-
ui::EventDispatchDetails DispatchFabricatedKeyEvent(ui::KeyEvent* event);
// Asks the client to confirm current composition text.
@@ -118,21 +95,11 @@ class UI_BASE_IME_EXPORT InputMethodWin : public InputMethodBase {
// (See "ui/base/ime/win/ime_input.h" for its details.)
ui::IMM32Manager imm32_manager_;
- // The toplevel window handle.
- // On non-Aura environment, this value is not used and always NULL.
- const HWND toplevel_window_handle_;
-
// The new text direction and layout alignment requested by the user by
// pressing ctrl-shift. It'll be sent to the text input client when the key
// is released.
base::i18n::TextDirection pending_requested_direction_;
- // Represents if WM_CHAR[wparam=='\r'] should be dispatched to the focused
- // text input client or ignored silently. This flag is introduced as a quick
- // workaround against crbug.com/319100
- // TODO(yukawa, IME): Figure out long-term solution.
- bool accept_carriage_return_;
-
// True when an IME should be allowed to process key events.
bool enabled_;
diff --git a/chromium/ui/base/ime/input_method_win_base.cc b/chromium/ui/base/ime/input_method_win_base.cc
new file mode 100644
index 00000000000..0e89451afb3
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_win_base.cc
@@ -0,0 +1,276 @@
+// 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_win_base.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <cwctype>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "ui/base/ime/ime_bridge.h"
+#include "ui/base/ime/ime_engine_handler_interface.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/win/tsf_input_scope.h"
+#include "ui/display/win/screen_win.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/win/hwnd_util.h"
+
+namespace ui {
+namespace {
+
+// Extra number of chars before and after selection (or composition) range which
+// is returned to IME for improving conversion accuracy.
+constexpr size_t kExtraNumberOfChars = 20;
+
+} // namespace
+
+InputMethodWinBase::InputMethodWinBase(internal::InputMethodDelegate* delegate,
+ HWND toplevel_window_handle)
+ : InputMethodBase(delegate),
+ toplevel_window_handle_(toplevel_window_handle) {}
+
+InputMethodWinBase::~InputMethodWinBase() {}
+
+void InputMethodWinBase::OnDidChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* focused) {
+ if (focused_before != focused)
+ accept_carriage_return_ = false;
+}
+
+bool InputMethodWinBase::IsWindowFocused(const TextInputClient* client) const {
+ if (!client)
+ return false;
+ // When Aura is enabled, |attached_window_handle| should always be a top-level
+ // window. So we can safely assume that |attached_window_handle| is ready for
+ // receiving keyboard input as long as it is an active window. This works well
+ // even when the |attached_window_handle| becomes active but has not received
+ // WM_FOCUS yet.
+ return toplevel_window_handle_ &&
+ GetActiveWindow() == toplevel_window_handle_;
+}
+
+LRESULT InputMethodWinBase::OnChar(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ const PlatformEvent& event,
+ BOOL* handled) {
+ *handled = TRUE;
+
+ // We need to send character events to the focused text input client event if
+ // its text input type is ui::TEXT_INPUT_TYPE_NONE.
+ if (GetTextInputClient()) {
+ const base::char16 kCarriageReturn = L'\r';
+ const base::char16 ch = static_cast<base::char16>(wparam);
+ // A mask to determine the previous key state from |lparam|. The value is 1
+ // if the key is down before the message is sent, or it is 0 if the key is
+ // up.
+ const uint32_t kPrevKeyDownBit = 0x40000000;
+ if (ch == kCarriageReturn && !(lparam & kPrevKeyDownBit))
+ accept_carriage_return_ = true;
+ // Conditionally ignore '\r' events to work around https://crbug.com/319100.
+ // TODO(yukawa, IME): Figure out long-term solution.
+ if (ch != kCarriageReturn || accept_carriage_return_) {
+ ui::KeyEvent char_event(event);
+ GetTextInputClient()->InsertChar(char_event);
+ }
+ }
+
+ // Explicitly show the system menu at a good location on [Alt]+[Space].
+ // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system
+ // menu causes undesirable titlebar artifacts in the classic theme.
+ if (message == WM_SYSCHAR && wparam == VK_SPACE)
+ gfx::ShowSystemMenu(window_handle);
+
+ return 0;
+}
+
+LRESULT InputMethodWinBase::OnImeRequest(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ *handled = FALSE;
+
+ // Should not receive WM_IME_REQUEST message, if IME is disabled.
+ const ui::TextInputType type = GetTextInputType();
+ if (type == ui::TEXT_INPUT_TYPE_NONE ||
+ type == ui::TEXT_INPUT_TYPE_PASSWORD) {
+ return 0;
+ }
+
+ switch (wparam) {
+ case IMR_RECONVERTSTRING:
+ *handled = TRUE;
+ return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
+ case IMR_DOCUMENTFEED:
+ *handled = TRUE;
+ return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
+ case IMR_QUERYCHARPOSITION:
+ *handled = TRUE;
+ return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
+ default:
+ return 0;
+ }
+}
+
+LRESULT InputMethodWinBase::OnDocumentFeed(RECONVERTSTRING* reconv) {
+ ui::TextInputClient* client = GetTextInputClient();
+ if (!client)
+ return 0;
+
+ gfx::Range text_range;
+ if (!client->GetTextRange(&text_range) || text_range.is_empty())
+ return 0;
+
+ bool result = false;
+ gfx::Range target_range;
+ if (client->HasCompositionText())
+ result = client->GetCompositionTextRange(&target_range);
+
+ if (!result || target_range.is_empty()) {
+ if (!client->GetSelectionRange(&target_range) || !target_range.IsValid()) {
+ return 0;
+ }
+ }
+
+ if (!text_range.Contains(target_range))
+ return 0;
+
+ if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars)
+ text_range.set_start(target_range.GetMin() - kExtraNumberOfChars);
+
+ if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars)
+ text_range.set_end(target_range.GetMax() + kExtraNumberOfChars);
+
+ size_t len = text_range.length();
+ size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
+
+ if (!reconv)
+ return need_size;
+
+ if (reconv->dwSize < need_size)
+ return 0;
+
+ base::string16 text;
+ if (!GetTextInputClient()->GetTextFromRange(text_range, &text))
+ return 0;
+ DCHECK_EQ(text_range.length(), text.length());
+
+ reconv->dwVersion = 0;
+ reconv->dwStrLen = len;
+ reconv->dwStrOffset = sizeof(RECONVERTSTRING);
+ reconv->dwCompStrLen =
+ client->HasCompositionText() ? target_range.length() : 0;
+ reconv->dwCompStrOffset =
+ (target_range.GetMin() - text_range.start()) * sizeof(WCHAR);
+ reconv->dwTargetStrLen = target_range.length();
+ reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
+
+ memcpy((char*)reconv + sizeof(RECONVERTSTRING), text.c_str(),
+ len * sizeof(WCHAR));
+
+ // According to Microsoft API document, IMR_RECONVERTSTRING and
+ // IMR_DOCUMENTFEED should return reconv, but some applications return
+ // need_size.
+ return reinterpret_cast<LRESULT>(reconv);
+}
+
+LRESULT InputMethodWinBase::OnReconvertString(RECONVERTSTRING* reconv) {
+ ui::TextInputClient* client = GetTextInputClient();
+ if (!client)
+ return 0;
+
+ // If there is a composition string already, we don't allow reconversion.
+ if (client->HasCompositionText())
+ return 0;
+
+ gfx::Range text_range;
+ if (!client->GetTextRange(&text_range) || text_range.is_empty())
+ return 0;
+
+ gfx::Range selection_range;
+ if (!client->GetSelectionRange(&selection_range) ||
+ selection_range.is_empty()) {
+ return 0;
+ }
+
+ DCHECK(text_range.Contains(selection_range));
+
+ size_t len = selection_range.length();
+ size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
+
+ if (!reconv)
+ return need_size;
+
+ if (reconv->dwSize < need_size)
+ return 0;
+
+ // TODO(penghuang): Return some extra context to help improve IME's
+ // reconversion accuracy.
+ base::string16 text;
+ if (!GetTextInputClient()->GetTextFromRange(selection_range, &text))
+ return 0;
+ DCHECK_EQ(selection_range.length(), text.length());
+
+ reconv->dwVersion = 0;
+ reconv->dwStrLen = len;
+ reconv->dwStrOffset = sizeof(RECONVERTSTRING);
+ reconv->dwCompStrLen = len;
+ reconv->dwCompStrOffset = 0;
+ reconv->dwTargetStrLen = len;
+ reconv->dwTargetStrOffset = 0;
+
+ memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
+ text.c_str(), len * sizeof(WCHAR));
+
+ // According to Microsoft API document, IMR_RECONVERTSTRING and
+ // IMR_DOCUMENTFEED should return reconv, but some applications return
+ // need_size.
+ return reinterpret_cast<LRESULT>(reconv);
+}
+
+LRESULT InputMethodWinBase::OnQueryCharPosition(IMECHARPOSITION* char_positon) {
+ if (!char_positon)
+ return 0;
+
+ if (char_positon->dwSize < sizeof(IMECHARPOSITION))
+ return 0;
+
+ ui::TextInputClient* client = GetTextInputClient();
+ if (!client)
+ return 0;
+
+ // Tentatively assume that the returned value from |client| is DIP (Density
+ // Independent Pixel). See the comment in text_input_client.h and
+ // http://crbug.com/360334.
+ gfx::Rect dip_rect;
+ if (client->HasCompositionText()) {
+ if (!client->GetCompositionCharacterBounds(char_positon->dwCharPos,
+ &dip_rect)) {
+ return 0;
+ }
+ } else {
+ // If there is no composition and the first character is queried, returns
+ // the caret bounds. This behavior is the same to that of RichEdit control.
+ if (char_positon->dwCharPos != 0)
+ return 0;
+ dip_rect = client->GetCaretBounds();
+ }
+ const gfx::Rect rect = display::win::ScreenWin::DIPToScreenRect(
+ toplevel_window_handle_, dip_rect);
+
+ char_positon->pt.x = rect.x();
+ char_positon->pt.y = rect.y();
+ char_positon->cLineHeight = rect.height();
+ return 1; // returns non-zero value when succeeded.
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_win_base.h b/chromium/ui/base/ime/input_method_win_base.h
new file mode 100644
index 00000000000..9e63213046e
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_win_base.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_INPUT_METHOD_WIN_BASE_H_
+#define UI_BASE_IME_INPUT_METHOD_WIN_BASE_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "ui/base/ime/input_method_base.h"
+#include "ui/base/ime/win/imm32_manager.h"
+
+namespace ui {
+
+// A common InputMethod base implementation for Windows.
+class UI_BASE_IME_EXPORT InputMethodWinBase : public InputMethodBase {
+ public:
+ InputMethodWinBase(internal::InputMethodDelegate* delegate,
+ HWND toplevel_window_handle);
+ ~InputMethodWinBase() override;
+
+ protected:
+ void OnDidChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) override;
+
+ // Returns true if the Win32 native window bound to |client| is considered
+ // to be ready for receiving keyboard input.
+ bool IsWindowFocused(const TextInputClient* client) const;
+
+ // For both WM_CHAR and WM_SYSCHAR
+ LRESULT OnChar(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ const PlatformEvent& event,
+ BOOL* handled);
+
+ // Some IMEs rely on WM_IME_REQUEST message even when TSF is enabled. So
+ // OnImeRequest (and its actual implementations as OnDocumentFeed,
+ // OnReconvertString, and OnQueryCharPosition) are placed in this base class.
+ LRESULT OnImeRequest(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled);
+ LRESULT OnDocumentFeed(RECONVERTSTRING* reconv);
+ LRESULT OnReconvertString(RECONVERTSTRING* reconv);
+ LRESULT OnQueryCharPosition(IMECHARPOSITION* char_positon);
+
+ // The toplevel window handle.
+ const HWND toplevel_window_handle_;
+
+ // Represents if WM_CHAR[wparam=='\r'] should be dispatched to the focused
+ // text input client or ignored silently. This flag is introduced as a quick
+ // workaround against https://crbug.com/319100
+ // TODO(yukawa, IME): Figure out long-term solution.
+ bool accept_carriage_return_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodWinBase);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_INPUT_METHOD_WIN_BASE_H_
diff --git a/chromium/ui/base/ime/input_method_win_tsf.cc b/chromium/ui/base/ime/input_method_win_tsf.cc
new file mode 100644
index 00000000000..0cf6f88e39f
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_win_tsf.cc
@@ -0,0 +1,147 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/input_method_win_tsf.h"
+
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/win/tsf_bridge.h"
+#include "ui/base/ime/win/tsf_event_router.h"
+
+namespace ui {
+
+class InputMethodWinTSF::TSFEventObserver : public TSFEventRouterObserver {
+ public:
+ TSFEventObserver() = default;
+
+ // Returns true if we know for sure that a candidate window (or IME suggest,
+ // etc.) is open.
+ bool IsCandidatePopupOpen() const { return is_candidate_popup_open_; }
+
+ // Overridden from TSFEventRouterObserver:
+ void OnCandidateWindowCountChanged(size_t window_count) override {
+ is_candidate_popup_open_ = (window_count != 0);
+ }
+
+ private:
+ // True if we know for sure that a candidate window is open.
+ bool is_candidate_popup_open_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TSFEventObserver);
+};
+
+InputMethodWinTSF::InputMethodWinTSF(internal::InputMethodDelegate* delegate,
+ HWND toplevel_window_handle)
+ : InputMethodWinBase(delegate, toplevel_window_handle),
+ tsf_event_observer_(new TSFEventObserver()),
+ tsf_event_router_(new TSFEventRouter(tsf_event_observer_.get())) {}
+
+InputMethodWinTSF::~InputMethodWinTSF() {}
+
+ui::EventDispatchDetails InputMethodWinTSF::DispatchKeyEvent(
+ ui::KeyEvent* event) {
+ // TODO(dtapuska): Handle WM_CHAR events.
+ return ui::EventDispatchDetails();
+}
+
+void InputMethodWinTSF::OnFocus() {
+ tsf_event_router_->SetManager(
+ ui::TSFBridge::GetInstance()->GetThreadManager().Get());
+}
+
+void InputMethodWinTSF::OnBlur() {
+ tsf_event_router_->SetManager(nullptr);
+}
+
+bool InputMethodWinTSF::OnUntranslatedIMEMessage(
+ const MSG event,
+ InputMethod::NativeEventResult* result) {
+ LRESULT original_result = 0;
+ BOOL handled = FALSE;
+ // Even when TSF is enabled, following IMM32/Win32 messages must be handled.
+ switch (event.message) {
+ case WM_IME_REQUEST:
+ // Some TSF-native TIPs (Text Input Processors) such as ATOK and Mozc
+ // still rely on WM_IME_REQUEST message to implement reverse conversion.
+ original_result =
+ OnImeRequest(event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ // ui::InputMethod interface is responsible for handling Win32 character
+ // messages. For instance, we will be here in the following cases.
+ // - TIP is not activated. (e.g, the current language profile is English)
+ // - TIP does not handle and WM_KEYDOWN and WM_KEYDOWN is translated into
+ // WM_CHAR by TranslateMessage API. (e.g, TIP is turned off)
+ // - Another application sends WM_CHAR through SendMessage API.
+ original_result = OnChar(event.hwnd, event.message, event.wParam,
+ event.lParam, event, &handled);
+ break;
+ }
+
+ if (result)
+ *result = original_result;
+ return !!handled;
+}
+
+void InputMethodWinTSF::OnTextInputTypeChanged(const TextInputClient* client) {
+ if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
+ return;
+ ui::TSFBridge::GetInstance()->CancelComposition();
+ ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client);
+}
+
+void InputMethodWinTSF::OnCaretBoundsChanged(const TextInputClient* client) {
+ if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
+ return;
+ ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
+}
+
+void InputMethodWinTSF::CancelComposition(const TextInputClient* client) {
+ if (IsTextInputClientFocused(client) && IsWindowFocused(client))
+ ui::TSFBridge::GetInstance()->CancelComposition();
+}
+
+void InputMethodWinTSF::DetachTextInputClient(TextInputClient* client) {
+ InputMethodWinBase::DetachTextInputClient(client);
+ ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
+}
+
+bool InputMethodWinTSF::IsCandidatePopupOpen() const {
+ return tsf_event_observer_->IsCandidatePopupOpen();
+}
+
+void InputMethodWinTSF::OnWillChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* focused) {
+ if (IsWindowFocused(focused_before)) {
+ ConfirmCompositionText();
+ ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before);
+ }
+}
+
+void InputMethodWinTSF::OnDidChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* focused) {
+ if (IsWindowFocused(focused) && IsTextInputClientFocused(focused)) {
+ ui::TSFBridge::GetInstance()->SetFocusedClient(toplevel_window_handle_,
+ focused);
+
+ // Force to update the input type since client's TextInputStateChanged()
+ // function might not be called if text input types before the client loses
+ // focus and after it acquires focus again are the same.
+ OnTextInputTypeChanged(focused);
+
+ // Force to update caret bounds, in case the client thinks that the caret
+ // bounds has not changed.
+ OnCaretBoundsChanged(focused);
+ }
+ InputMethodWinBase::OnDidChangeFocusedClient(focused_before, focused);
+}
+
+void InputMethodWinTSF::ConfirmCompositionText() {
+ if (!IsTextInputTypeNone())
+ ui::TSFBridge::GetInstance()->ConfirmComposition();
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_win_tsf.h b/chromium/ui/base/ime/input_method_win_tsf.h
new file mode 100644
index 00000000000..4d8a7c465bd
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_win_tsf.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_INPUT_METHOD_WIN_TSF_H_
+#define UI_BASE_IME_INPUT_METHOD_WIN_TSF_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "ui/base/ime/input_method_win_base.h"
+
+namespace ui {
+
+class TSFEventRouter;
+
+// An InputMethod implementation based on Windows TSF API.
+class UI_BASE_IME_EXPORT InputMethodWinTSF : public InputMethodWinBase {
+ public:
+ InputMethodWinTSF(internal::InputMethodDelegate* delegate,
+ HWND toplevel_window_handle);
+ ~InputMethodWinTSF() override;
+
+ // Overridden from InputMethod:
+ ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
+ void OnFocus() override;
+ void OnBlur() override;
+ bool OnUntranslatedIMEMessage(const MSG event,
+ NativeEventResult* result) override;
+ void OnTextInputTypeChanged(const TextInputClient* client) override;
+ void OnCaretBoundsChanged(const TextInputClient* client) override;
+ void CancelComposition(const TextInputClient* client) override;
+ void DetachTextInputClient(TextInputClient* client) override;
+ bool IsCandidatePopupOpen() const override;
+
+ // Overridden from InputMethodBase:
+ void OnWillChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) override;
+ void OnDidChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) override;
+
+ private:
+ class TSFEventObserver;
+
+ // Asks the client to confirm current composition text.
+ void ConfirmCompositionText();
+
+ // TSF event router and observer.
+ std::unique_ptr<TSFEventObserver> tsf_event_observer_;
+ std::unique_ptr<TSFEventRouter> tsf_event_router_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodWinTSF);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_INPUT_METHOD_WIN_TSF_H_
diff --git a/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc b/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
index ec651ce0c04..f8d3102ee48 100644
--- a/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
+++ b/chromium/ui/base/ime/linux/fake_input_method_context_factory.cc
@@ -4,7 +4,6 @@
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/ime/linux/fake_input_method_context.h"
namespace ui {
diff --git a/chromium/ui/base/ime/mock_input_method.cc b/chromium/ui/base/ime/mock_input_method.cc
index 43d6b07f516..79ae727e400 100644
--- a/chromium/ui/base/ime/mock_input_method.cc
+++ b/chromium/ui/base/ime/mock_input_method.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ui/base/ime/mock_input_method.h"
+#include "build/build_config.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/events/event.h"
@@ -55,12 +56,14 @@ void MockInputMethod::OnBlur() {
observer.OnBlur();
}
-bool MockInputMethod::OnUntranslatedIMEMessage(const base::NativeEvent& event,
+#if defined(OS_WIN)
+bool MockInputMethod::OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) {
if (result)
*result = NativeEventResult();
return false;
}
+#endif
void MockInputMethod::OnTextInputTypeChanged(const TextInputClient* client) {
for (InputMethodObserver& observer : observer_list_)
diff --git a/chromium/ui/base/ime/mock_input_method.h b/chromium/ui/base/ime/mock_input_method.h
index b841a7a1d26..d3058a4608f 100644
--- a/chromium/ui/base/ime/mock_input_method.h
+++ b/chromium/ui/base/ime/mock_input_method.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "build/build_config.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/base/ime/ui_base_ime_export.h"
@@ -32,8 +33,12 @@ class UI_BASE_IME_EXPORT MockInputMethod : public InputMethod {
void SetDelegate(internal::InputMethodDelegate* delegate) override;
void OnFocus() override;
void OnBlur() override;
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+
+#if defined(OS_WIN)
+ bool OnUntranslatedIMEMessage(const MSG event,
NativeEventResult* result) override;
+#endif
+
void SetFocusedTextInputClient(TextInputClient* client) override;
void DetachTextInputClient(TextInputClient* client) override;
TextInputClient* GetTextInputClient() const override;
diff --git a/chromium/ui/base/ime/win/imm32_manager.cc b/chromium/ui/base/ime/win/imm32_manager.cc
index ed9b186d6c6..9f9e6548840 100644
--- a/chromium/ui/base/ime/win/imm32_manager.cc
+++ b/chromium/ui/base/ime/win/imm32_manager.cc
@@ -78,13 +78,13 @@ void GetImeTextSpans(HIMC imm_context,
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.thick = false;
+ ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThin;
ime_text_span.background_color = SK_ColorTRANSPARENT;
// Use thick underline for the target clause.
if (ime_text_span.start_offset >= static_cast<uint32_t>(target_start) &&
ime_text_span.end_offset <= static_cast<uint32_t>(target_end)) {
- ime_text_span.thick = true;
+ ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThick;
}
ime_text_spans->push_back(ime_text_span);
}
@@ -330,24 +330,24 @@ void IMM32Manager::GetCompositionInfo(HIMC imm_context,
return;
ImeTextSpan ime_text_span;
- ime_text_span.underline_color = SK_ColorBLACK;
+ ime_text_span.underline_color = SK_ColorTRANSPARENT;
ime_text_span.background_color = SK_ColorTRANSPARENT;
if (target_start > 0) {
ime_text_span.start_offset = 0U;
ime_text_span.end_offset = static_cast<uint32_t>(target_start);
- ime_text_span.thick = false;
+ ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThin;
composition->ime_text_spans.push_back(ime_text_span);
}
if (target_end > target_start) {
ime_text_span.start_offset = static_cast<uint32_t>(target_start);
ime_text_span.end_offset = static_cast<uint32_t>(target_end);
- ime_text_span.thick = true;
+ ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThick;
composition->ime_text_spans.push_back(ime_text_span);
}
if (target_end < length) {
ime_text_span.start_offset = static_cast<uint32_t>(target_end);
ime_text_span.end_offset = static_cast<uint32_t>(length);
- ime_text_span.thick = false;
+ ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThin;
composition->ime_text_spans.push_back(ime_text_span);
}
}
diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.cc b/chromium/ui/base/ime/win/mock_tsf_bridge.cc
new file mode 100644
index 00000000000..a69f37603e6
--- /dev/null
+++ b/chromium/ui/base/ime/win/mock_tsf_bridge.cc
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/win/mock_tsf_bridge.h"
+
+#include "base/logging.h"
+#include "ui/base/ime/text_input_client.h"
+
+namespace ui {
+
+MockTSFBridge::MockTSFBridge() = default;
+
+MockTSFBridge::~MockTSFBridge() = default;
+
+bool MockTSFBridge::CancelComposition() {
+ ++cancel_composition_call_count_;
+ return true;
+}
+
+bool MockTSFBridge::ConfirmComposition() {
+ ++confirm_composition_call_count_;
+ return true;
+}
+
+void MockTSFBridge::OnTextInputTypeChanged(const TextInputClient* client) {
+ latest_text_input_type_ = client->GetTextInputType();
+}
+
+void MockTSFBridge::OnTextLayoutChanged() {
+ ++on_text_layout_changed_;
+}
+
+void MockTSFBridge::SetFocusedClient(HWND focused_window,
+ TextInputClient* client) {
+ ++set_focused_client_call_count_;
+ focused_window_ = focused_window;
+ text_input_client_ = client;
+}
+
+void MockTSFBridge::RemoveFocusedClient(TextInputClient* client) {
+ ++remove_focused_client_call_count_;
+ DCHECK_EQ(client, text_input_client_);
+ text_input_client_ = nullptr;
+ focused_window_ = nullptr;
+}
+
+Microsoft::WRL::ComPtr<ITfThreadMgr> MockTSFBridge::GetThreadManager() {
+ return thread_manager_;
+}
+
+TextInputClient* MockTSFBridge::GetFocusedTextInputClient() const {
+ return text_input_client_;
+}
+
+void MockTSFBridge::Reset() {
+ enable_ime_call_count_ = 0;
+ disable_ime_call_count_ = 0;
+ cancel_composition_call_count_ = 0;
+ confirm_composition_call_count_ = 0;
+ on_text_layout_changed_ = 0;
+ associate_focus_call_count_ = 0;
+ set_focused_client_call_count_ = 0;
+ remove_focused_client_call_count_ = 0;
+ text_input_client_ = nullptr;
+ focused_window_ = nullptr;
+ latest_text_input_type_ = TEXT_INPUT_TYPE_NONE;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.h b/chromium/ui/base/ime/win/mock_tsf_bridge.h
new file mode 100644
index 00000000000..5baca1ade05
--- /dev/null
+++ b/chromium/ui/base/ime/win/mock_tsf_bridge.h
@@ -0,0 +1,99 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_
+#define UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_
+
+#include <msctf.h>
+#include <wrl/client.h>
+
+#include "base/compiler_specific.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/base/ime/win/tsf_bridge.h"
+
+namespace ui {
+
+class MockTSFBridge : public TSFBridge {
+ public:
+ MockTSFBridge();
+ ~MockTSFBridge() override;
+
+ // TSFBridge:
+ bool CancelComposition() override;
+ bool ConfirmComposition() override;
+ void OnTextInputTypeChanged(const TextInputClient* client) override;
+ void OnTextLayoutChanged() override;
+ void SetFocusedClient(HWND focused_window, TextInputClient* client) override;
+ void RemoveFocusedClient(TextInputClient* client) override;
+ Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override;
+ TextInputClient* GetFocusedTextInputClient() const override;
+
+ // Resets MockTSFBridge state including function call counter.
+ void Reset();
+
+ // Call count of EnableIME().
+ unsigned enable_ime_call_count() const { return enable_ime_call_count_; }
+
+ // Call count of DisableIME().
+ unsigned disable_ime_call_count() const { return disable_ime_call_count_; }
+
+ // Call count of CancelComposition().
+ unsigned cancel_composition_call_count() const {
+ return cancel_composition_call_count_;
+ }
+
+ // Call count of ConfirmComposition().
+ unsigned confirm_composition_call_count() const {
+ return confirm_composition_call_count_;
+ }
+
+ // Call count of OnTextLayoutChanged().
+ unsigned on_text_layout_changed() const { return on_text_layout_changed_; }
+
+ // Call count of AssociateFocus().
+ unsigned associate_focus_call_count() const {
+ return associate_focus_call_count_;
+ }
+
+ // Call count of SetFocusClient().
+ unsigned set_focused_client_call_count() const {
+ return set_focused_client_call_count_;
+ }
+
+ // Call count of RemoveFocusedClient().
+ unsigned remove_focused_client_call_count() const {
+ return remove_focused_client_call_count_;
+ }
+
+ // Returns current TextInputClient.
+ TextInputClient* text_input_clinet() const { return text_input_client_; }
+
+ // Returns currently focused window handle.
+ HWND focused_window() const { return focused_window_; }
+
+ // Returns latest text input type.
+ TextInputType latest_text_iput_type() const {
+ return latest_text_input_type_;
+ }
+
+ private:
+ unsigned enable_ime_call_count_ = 0;
+ unsigned disable_ime_call_count_ = 0;
+ unsigned cancel_composition_call_count_ = 0;
+ unsigned confirm_composition_call_count_ = 0;
+ unsigned on_text_layout_changed_ = 0;
+ unsigned associate_focus_call_count_ = 0;
+ unsigned set_focused_client_call_count_ = 0;
+ unsigned remove_focused_client_call_count_ = 0;
+ TextInputClient* text_input_client_ = nullptr;
+ HWND focused_window_ = nullptr;
+ TextInputType latest_text_input_type_ = TEXT_INPUT_TYPE_NONE;
+ Microsoft::WRL::ComPtr<ITfThreadMgr> thread_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockTSFBridge);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.cc
new file mode 100644
index 00000000000..ef3d5a82793
--- /dev/null
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_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/win/on_screen_keyboard_display_manager_stub.h"
+
+namespace ui {
+
+// OnScreenKeyboardDisplayManagerStub member definitions.
+OnScreenKeyboardDisplayManagerStub::OnScreenKeyboardDisplayManagerStub() {}
+
+OnScreenKeyboardDisplayManagerStub::~OnScreenKeyboardDisplayManagerStub() {}
+
+bool OnScreenKeyboardDisplayManagerStub::DisplayVirtualKeyboard(
+ OnScreenKeyboardObserver* observer) {
+ return false;
+}
+
+bool OnScreenKeyboardDisplayManagerStub::DismissVirtualKeyboard() {
+ return false;
+}
+
+void OnScreenKeyboardDisplayManagerStub::RemoveObserver(
+ OnScreenKeyboardObserver* observer) {}
+
+bool OnScreenKeyboardDisplayManagerStub::IsKeyboardVisible() const {
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.h
new file mode 100644
index 00000000000..184f8067a1e
--- /dev/null
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_stub.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_STUB_H_
+#define UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_STUB_H_
+
+#include "ui/base/ime/ui_base_ime_export.h"
+#include "ui/base/ime/win/osk_display_manager.h"
+
+namespace ui {
+
+// This class provides a stub OnScreenDisplayManager.
+// Used for < Win8 OS versions.
+class UI_BASE_IME_EXPORT OnScreenKeyboardDisplayManagerStub
+ : public OnScreenKeyboardDisplayManager {
+ public:
+ ~OnScreenKeyboardDisplayManagerStub() override;
+
+ // OnScreenKeyboardDisplayManager overrides.
+ bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer) final;
+ bool DismissVirtualKeyboard() final;
+ void RemoveObserver(OnScreenKeyboardObserver* observer) final;
+ bool IsKeyboardVisible() const final;
+
+ private:
+ friend class OnScreenKeyboardDisplayManager;
+ OnScreenKeyboardDisplayManagerStub();
+
+ DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManagerStub);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_STUB_H_
diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
index bbce7bda6eb..f1fcd63e3c1 100644
--- a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/win/osk_display_manager.h"
+#include "ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h"
#include <windows.h>
+
#include <shellapi.h>
#include <shlobj.h>
#include <shobjidl.h> // Must be before propkey.
#include "base/bind.h"
-#include "base/debug/leak_annotations.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
@@ -20,15 +20,17 @@
#include "base/win/scoped_co_mem.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
+#include "ui/base/ime/win/osk_display_observer.h"
#include "ui/base/win/hidden_window.h"
-#include "ui/base/win/osk_display_observer.h"
-#include "ui/display/win/dpi.h"
+#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/dip_util.h"
namespace {
-constexpr int kCheckOSKDelayMs = 1000;
-constexpr int kDismissKeyboardRetryTimeoutMs = 100;
+constexpr base::TimeDelta kCheckOSKDelay =
+ base::TimeDelta::FromMilliseconds(1000);
+constexpr base::TimeDelta kDismissKeyboardRetryTimeout =
+ base::TimeDelta::FromMilliseconds(100);
constexpr int kDismissKeyboardMaxRetries = 5;
constexpr wchar_t kOSKClassName[] = L"IPTip_Main_Window";
@@ -64,10 +66,13 @@ class OnScreenKeyboardDetector {
void AddObserver(OnScreenKeyboardObserver* observer);
void RemoveObserver(OnScreenKeyboardObserver* observer);
- // Returns true if the osk is visible. Sets osk bounding rect if non-null
- static bool IsKeyboardVisible(gfx::Rect* osk_bounding_rect);
+ // Returns true if the osk is visible.
+ static bool IsKeyboardVisible();
private:
+ // Returns the occluded rect in dips.
+ gfx::Rect GetOccludedRect();
+
// Executes as a task and detects if the on screen keyboard is displayed.
// Once the keyboard is displayed it schedules the HideIfNecessary() task to
// detect when the keyboard is or should be hidden.
@@ -80,7 +85,7 @@ class OnScreenKeyboardDetector {
// Notifies observers that the keyboard was displayed.
// A recurring task HideIfNecessary() is started to detect when the OSK
// disappears.
- void HandleKeyboardVisible();
+ void HandleKeyboardVisible(const gfx::Rect& occluded_rect);
// Notifies observers that the keyboard was hidden.
// The observer list is cleared out after this notification.
@@ -95,9 +100,6 @@ class OnScreenKeyboardDetector {
// Tracks if the keyboard was displayed.
bool osk_visible_notification_received_ = false;
- // The keyboard dimensions in pixels.
- gfx::Rect osk_rect_pixels_;
-
// Set to true if a call to DetectKeyboard() was made.
bool keyboard_detect_requested_ = false;
@@ -131,14 +133,14 @@ void OnScreenKeyboardDetector::DetectKeyboard(HWND main_window) {
// a delayed task to check if the keyboard is visible because of the possible
// delay between the ShellExecute call and the keyboard becoming visible.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::CheckIfKeyboardVisible,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
+ FROM_HERE,
+ base::BindOnce(&OnScreenKeyboardDetector::CheckIfKeyboardVisible,
+ keyboard_detector_factory_.GetWeakPtr()),
+ kCheckOSKDelay);
}
bool OnScreenKeyboardDetector::DismissKeyboard() {
- // We dismiss the virtual keyboard by generating the ESC keystroke
- // programmatically.
+ // We dismiss the virtual keyboard by generating the SC_CLOSE.
HWND osk = ::FindWindow(kOSKClassName, nullptr);
if (::IsWindow(osk) && ::IsWindowEnabled(osk)) {
keyboard_detect_requested_ = false;
@@ -146,16 +148,19 @@ bool OnScreenKeyboardDetector::DismissKeyboard() {
HandleKeyboardHidden();
PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0);
return true;
- } else if (keyboard_detect_requested_) {
+ }
+
+ if (keyboard_detect_requested_) {
if (keyboard_dismiss_retry_count_ < kDismissKeyboardMaxRetries) {
keyboard_dismiss_retry_count_++;
// Please refer to the comments in the DetectKeyboard() function for more
// information as to why we need a delayed task here.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(base::IgnoreResult(
- &OnScreenKeyboardDetector::DismissKeyboard),
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kDismissKeyboardRetryTimeoutMs));
+ FROM_HERE,
+ base::BindOnce(
+ base::IgnoreResult(&OnScreenKeyboardDetector::DismissKeyboard),
+ keyboard_detector_factory_.GetWeakPtr()),
+ kDismissKeyboardRetryTimeout);
} else {
keyboard_dismiss_retry_count_ = 0;
}
@@ -173,24 +178,41 @@ void OnScreenKeyboardDetector::RemoveObserver(
}
// static
-bool OnScreenKeyboardDetector::IsKeyboardVisible(gfx::Rect* osk_bounding_rect) {
+bool OnScreenKeyboardDetector::IsKeyboardVisible() {
HWND osk = ::FindWindow(kOSKClassName, nullptr);
if (!::IsWindow(osk))
return false;
- if (osk_bounding_rect) {
- RECT osk_rect = {};
- ::GetWindowRect(osk, &osk_rect);
- *osk_bounding_rect = gfx::Rect(osk_rect);
- }
return ::IsWindowVisible(osk) && ::IsWindowEnabled(osk);
}
+gfx::Rect OnScreenKeyboardDetector::GetOccludedRect() {
+ gfx::Rect occluded_rect;
+ HWND osk = ::FindWindow(kOSKClassName, nullptr);
+ if (!::IsWindow(osk) || !::IsWindowVisible(osk) || !::IsWindowEnabled(osk))
+ return occluded_rect;
+
+ RECT osk_rect = {};
+ RECT main_window_rect = {};
+ if (!::GetWindowRect(osk, &osk_rect) ||
+ !::GetWindowRect(main_window_, &main_window_rect)) {
+ return occluded_rect;
+ }
+
+ gfx::Rect gfx_osk_rect(osk_rect);
+ gfx::Rect gfx_main_window_rect(main_window_rect);
+
+ gfx_osk_rect.Intersect(gfx_main_window_rect);
+
+ return display::win::ScreenWin::ScreenToDIPRect(main_window_, gfx_osk_rect);
+}
+
void OnScreenKeyboardDetector::CheckIfKeyboardVisible() {
- if (IsKeyboardVisible(&osk_rect_pixels_)) {
+ gfx::Rect occluded_rect = GetOccludedRect();
+ if (!occluded_rect.IsEmpty()) {
if (!osk_visible_notification_received_)
- HandleKeyboardVisible();
+ HandleKeyboardVisible(occluded_rect);
} else {
- DVLOG(1) << "OSK did not come up in 1 second. Something wrong.";
+ DVLOG(1) << "OSK did not come up. Something wrong.";
}
}
@@ -221,30 +243,33 @@ void OnScreenKeyboardDetector::HideIfNecessary() {
}
} else {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
+ FROM_HERE,
+ base::BindOnce(&OnScreenKeyboardDetector::HideIfNecessary,
+ keyboard_detector_factory_.GetWeakPtr()),
+ kCheckOSKDelay);
}
}
-void OnScreenKeyboardDetector::HandleKeyboardVisible() {
+void OnScreenKeyboardDetector::HandleKeyboardVisible(
+ const gfx::Rect& occluded_rect) {
DCHECK(!osk_visible_notification_received_);
osk_visible_notification_received_ = true;
for (OnScreenKeyboardObserver& observer : observers_)
- observer.OnKeyboardVisible(osk_rect_pixels_);
+ observer.OnKeyboardVisible(occluded_rect);
// Now that the keyboard is visible, run the task to detect if it was hidden.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
+ FROM_HERE,
+ base::BindOnce(&OnScreenKeyboardDetector::HideIfNecessary,
+ keyboard_detector_factory_.GetWeakPtr()),
+ kCheckOSKDelay);
}
void OnScreenKeyboardDetector::HandleKeyboardHidden() {
osk_visible_notification_received_ = false;
for (OnScreenKeyboardObserver& observer : observers_)
- observer.OnKeyboardHidden(osk_rect_pixels_);
+ observer.OnKeyboardHidden();
ClearObservers();
}
@@ -253,25 +278,15 @@ void OnScreenKeyboardDetector::ClearObservers() {
RemoveObserver(&observer);
}
-// OnScreenKeyboardDisplayManager member definitions.
-OnScreenKeyboardDisplayManager::OnScreenKeyboardDisplayManager() {}
-
-OnScreenKeyboardDisplayManager::~OnScreenKeyboardDisplayManager() {}
-
-OnScreenKeyboardDisplayManager* OnScreenKeyboardDisplayManager::GetInstance() {
- static OnScreenKeyboardDisplayManager* instance = nullptr;
- if (!instance) {
- instance = new OnScreenKeyboardDisplayManager;
- ANNOTATE_LEAKING_OBJECT_PTR(instance);
- }
- return instance;
+// OnScreenKeyboardDisplayManagerTabTip member definitions.
+OnScreenKeyboardDisplayManagerTabTip::OnScreenKeyboardDisplayManagerTabTip() {
+ DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
}
-bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard(
- OnScreenKeyboardObserver* observer) {
- if (base::win::GetVersion() < base::win::VERSION_WIN8)
- return false;
+OnScreenKeyboardDisplayManagerTabTip::~OnScreenKeyboardDisplayManagerTabTip() {}
+bool OnScreenKeyboardDisplayManagerTabTip::DisplayVirtualKeyboard(
+ OnScreenKeyboardObserver* observer) {
if (base::win::IsKeyboardPresentOnSlate(nullptr, ui::GetHiddenWindow()))
return false;
@@ -287,7 +302,7 @@ bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard(
if (success) {
// If multiple calls to DisplayVirtualKeyboard occur one after the other,
// the last observer would be the one to get notifications.
- keyboard_detector_.reset(new OnScreenKeyboardDetector);
+ keyboard_detector_ = std::make_unique<OnScreenKeyboardDetector>();
if (observer)
keyboard_detector_->AddObserver(observer);
keyboard_detector_->DetectKeyboard(::GetForegroundWindow());
@@ -295,20 +310,18 @@ bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard(
return success;
}
-bool OnScreenKeyboardDisplayManager::DismissVirtualKeyboard() {
- if (base::win::GetVersion() < base::win::VERSION_WIN8)
- return false;
-
+bool OnScreenKeyboardDisplayManagerTabTip::DismissVirtualKeyboard() {
return keyboard_detector_ ? keyboard_detector_->DismissKeyboard() : false;
}
-void OnScreenKeyboardDisplayManager::RemoveObserver(
+void OnScreenKeyboardDisplayManagerTabTip::RemoveObserver(
OnScreenKeyboardObserver* observer) {
if (keyboard_detector_)
keyboard_detector_->RemoveObserver(observer);
}
-bool OnScreenKeyboardDisplayManager::GetOSKPath(base::string16* osk_path) {
+bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(
+ base::string16* osk_path) {
DCHECK(osk_path);
// We need to launch TabTip.exe from the location specified under the
@@ -372,8 +385,8 @@ bool OnScreenKeyboardDisplayManager::GetOSKPath(base::string16* osk_path) {
return !osk_path->empty();
}
-bool OnScreenKeyboardDisplayManager::IsKeyboardVisible() const {
- return OnScreenKeyboardDetector::IsKeyboardVisible(nullptr);
+bool OnScreenKeyboardDisplayManagerTabTip::IsKeyboardVisible() const {
+ return OnScreenKeyboardDetector::IsKeyboardVisible();
}
} // namespace ui
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
new file mode 100644
index 00000000000..e63bf814456
--- /dev/null
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
@@ -0,0 +1,51 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_TAB_TIP_H_
+#define UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_TAB_TIP_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/strings/string16.h"
+#include "ui/base/ime/ui_base_ime_export.h"
+#include "ui/base/ime/win/osk_display_manager.h"
+
+namespace ui {
+
+class OnScreenKeyboardDetector;
+
+// This class provides an implementation of the OnScreenKeyboardDisplayManager
+// that uses heuristics and the TabTip.exe to display the on screen keyboard.
+// Used on Windows > 7 and Windows < 10.0.10240.0
+class UI_BASE_IME_EXPORT OnScreenKeyboardDisplayManagerTabTip
+ : public OnScreenKeyboardDisplayManager {
+ public:
+ ~OnScreenKeyboardDisplayManagerTabTip() override;
+
+ // OnScreenKeyboardDisplayManager overrides.
+ bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer) final;
+ bool DismissVirtualKeyboard() final;
+ void RemoveObserver(OnScreenKeyboardObserver* observer) final;
+ bool IsKeyboardVisible() const final;
+
+ // 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);
+
+ private:
+ friend class OnScreenKeyboardDisplayManager;
+ friend class OnScreenKeyboardTest;
+ OnScreenKeyboardDisplayManagerTabTip();
+
+ std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_;
+
+ // The location of TabTip.exe.
+ base::string16 osk_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManagerTabTip);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_TAB_TIP_H_
diff --git a/chromium/ui/base/win/osk_display_manager_unittest.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
index f9112c846ed..16d785f01a8 100644
--- a/chromium/ui/base/win/osk_display_manager_unittest.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/win/osk_display_manager.h"
+#include "ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -12,15 +12,26 @@
#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace ui {
+
+class OnScreenKeyboardTest : public ::testing::Test {
+ protected:
+ std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip>
+ CreateOSKDisplayManager() {
+ return std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip>(
+ new OnScreenKeyboardDisplayManagerTabTip());
+ }
+};
+
// This test validates the on screen keyboard path (tabtip.exe) which is read
// from the registry.
-TEST(OnScreenKeyboardTest, OSKPath) {
+TEST_F(OnScreenKeyboardTest, OSKPath) {
// The on screen keyboard is only available on Windows 8+.
if (base::win::GetVersion() < base::win::VERSION_WIN8)
return;
- ui::OnScreenKeyboardDisplayManager* keyboard_display_manager =
- ui::OnScreenKeyboardDisplayManager::GetInstance();
+ std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip>
+ keyboard_display_manager(CreateOSKDisplayManager());
EXPECT_NE(nullptr, keyboard_display_manager);
base::string16 osk_path;
@@ -38,3 +49,5 @@ TEST(OnScreenKeyboardTest, OSKPath) {
EXPECT_TRUE(base::PathExists(base::FilePath(osk_path)));
}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/osk_display_manager.cc b/chromium/ui/base/ime/win/osk_display_manager.cc
new file mode 100644
index 00000000000..e7b441c0eb1
--- /dev/null
+++ b/chromium/ui/base/ime/win/osk_display_manager.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/win/osk_display_manager.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/win/windows_version.h"
+#include "ui/base/ime/win/on_screen_keyboard_display_manager_stub.h"
+#include "ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h"
+
+namespace ui {
+
+// OnScreenKeyboardDisplayManager member definitions.
+OnScreenKeyboardDisplayManager::OnScreenKeyboardDisplayManager() {}
+
+OnScreenKeyboardDisplayManager::~OnScreenKeyboardDisplayManager() {}
+
+OnScreenKeyboardDisplayManager* OnScreenKeyboardDisplayManager::GetInstance() {
+ static OnScreenKeyboardDisplayManager* instance = nullptr;
+ if (!instance) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ instance = new OnScreenKeyboardDisplayManagerStub();
+ else
+ instance = new OnScreenKeyboardDisplayManagerTabTip();
+ ANNOTATE_LEAKING_OBJECT_PTR(instance);
+ }
+ return instance;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/win/osk_display_manager.h b/chromium/ui/base/ime/win/osk_display_manager.h
index b5392c4b686..489558669f3 100644
--- a/chromium/ui/base/win/osk_display_manager.h
+++ b/chromium/ui/base/ime/win/osk_display_manager.h
@@ -2,59 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
-#define UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
+#ifndef UI_BASE_IME_WIN_OSK_DISPLAY_MANAGER_H_
+#define UI_BASE_IME_WIN_OSK_DISPLAY_MANAGER_H_
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_base_export.h"
+#include "ui/base/ime/ui_base_ime_export.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
-class OnScreenKeyboardDetector;
class OnScreenKeyboardObserver;
// This class provides functionality to display the on screen keyboard on
// Windows 8+. It optionally notifies observers that the OSK is displayed,
// hidden, etc.
-class UI_BASE_EXPORT OnScreenKeyboardDisplayManager {
+class UI_BASE_IME_EXPORT OnScreenKeyboardDisplayManager {
public:
static OnScreenKeyboardDisplayManager* GetInstance();
- ~OnScreenKeyboardDisplayManager();
+ virtual ~OnScreenKeyboardDisplayManager();
// Functions to display and dismiss the keyboard.
// The optional |observer| parameter allows callers to be notified when the
// keyboard is displayed, dismissed, etc.
- bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer);
+ virtual bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer) = 0;
// When the keyboard is dismissed, the registered observer if any is removed
// after notifying it.
- bool DismissVirtualKeyboard();
+ virtual bool DismissVirtualKeyboard() = 0;
// Removes a registered observer.
- void RemoveObserver(OnScreenKeyboardObserver* observer);
-
- // 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);
+ virtual void RemoveObserver(OnScreenKeyboardObserver* observer) = 0;
// Returns true if the virtual keyboard is currently visible.
- bool IsKeyboardVisible() const;
+ virtual bool IsKeyboardVisible() const = 0;
- private:
+ protected:
OnScreenKeyboardDisplayManager();
-
- std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_;
-
- // The location of TabTip.exe.
- base::string16 osk_path_;
-
- DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManager);
};
} // namespace ui
-#endif // UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
+#endif // UI_BASE_IME_WIN_OSK_DISPLAY_MANAGER_H_
diff --git a/chromium/ui/base/win/osk_display_observer.h b/chromium/ui/base/ime/win/osk_display_observer.h
index 8c5d09205e9..8c83f567505 100644
--- a/chromium/ui/base/win/osk_display_observer.h
+++ b/chromium/ui/base/ime/win/osk_display_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_WIN_OSK_OBSERVER_H_
-#define UI_BASE_WIN_OSK_OBSERVER_H_
+#ifndef UI_BASE_IME_WIN_OSK_DISPLAY_OBSERVER_H_
+#define UI_BASE_IME_WIN_OSK_DISPLAY_OBSERVER_H_
namespace gfx {
class Rect;
@@ -13,16 +13,15 @@ namespace ui {
// Implemented by classes who wish to get notified about the on screen keyboard
// becoming visible/hidden.
-class UI_BASE_EXPORT OnScreenKeyboardObserver {
+class UI_BASE_IME_EXPORT OnScreenKeyboardObserver {
public:
virtual ~OnScreenKeyboardObserver() {}
- // The |keyboard_rect| parameter contains the bounds of the keyboard in
- // pixels.
- virtual void OnKeyboardVisible(const gfx::Rect& keyboard_rect_in_pixels) {}
- virtual void OnKeyboardHidden(const gfx::Rect& keyboard_rect_in_pixels) {}
+ // The |keyboard_rect| parameter contains the bounds of the keyboard in dips.
+ virtual void OnKeyboardVisible(const gfx::Rect& keyboard_rect) {}
+ virtual void OnKeyboardHidden() {}
};
} // namespace ui
-#endif // UI_BASE_WIN_OSK_OBSERVER_H_
+#endif // UI_BASE_IME_WIN_OSK_DISPLAY_OBSERVER_H_
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
new file mode 100644
index 00000000000..b5b1ba2a38d
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -0,0 +1,542 @@
+// 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 <msctf.h>
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/no_destructor.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/win/scoped_variant.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/win/tsf_bridge.h"
+#include "ui/base/ime/win/tsf_text_store.h"
+#include "ui/base/ui_base_features.h"
+
+namespace ui {
+
+namespace {
+
+// TSFBridgeImpl -----------------------------------------------------------
+
+// A TLS implementation of TSFBridge.
+class TSFBridgeImpl : public TSFBridge {
+ public:
+ TSFBridgeImpl();
+ ~TSFBridgeImpl() override;
+
+ bool Initialize();
+
+ // TsfBridge:
+ void OnTextInputTypeChanged(const TextInputClient* client) override;
+ void OnTextLayoutChanged() override;
+ bool CancelComposition() override;
+ bool ConfirmComposition() override;
+ void SetFocusedClient(HWND focused_window, TextInputClient* client) override;
+ void RemoveFocusedClient(TextInputClient* client) override;
+ Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override;
+ TextInputClient* GetFocusedTextInputClient() const override;
+
+ private:
+ // Returns true if |tsf_document_map_| is successfully initialized. This
+ // method should be called from and only from Initialize().
+ bool InitializeDocumentMapInternal();
+
+ // Returns true if |context| is successfully updated to be a disabled
+ // context, where an IME should be deactivated. This is suitable for some
+ // special input context such as password fields.
+ bool InitializeDisabledContext(ITfContext* context);
+
+ // Returns true if a TSF document manager and a TSF context is successfully
+ // created with associating with given |text_store|. The returned
+ // |source_cookie| indicates the binding between |text_store| and |context|.
+ // You can pass nullptr to |text_store| and |source_cookie| when text store is
+ // not necessary.
+ bool CreateDocumentManager(TSFTextStore* text_store,
+ ITfDocumentMgr** document_manager,
+ ITfContext** context,
+ DWORD* source_cookie);
+
+ // Returns true if |document_manager| is the focused document manager.
+ bool IsFocused(ITfDocumentMgr* document_manager);
+
+ // Returns true if already initialized.
+ bool IsInitialized();
+
+ // Updates or clears the association maintained in the TSF runtime between
+ // |attached_window_handle_| and the current document manager. Keeping this
+ // association updated solves some tricky event ordering issues between
+ // logical text input focus managed by Chrome and native text input focus
+ // managed by the OS.
+ // Background:
+ // TSF runtime monitors some Win32 messages such as WM_ACTIVATE to
+ // change the focused document manager. This is problematic when
+ // TSFBridge::SetFocusedClient is called first then the target window
+ // receives WM_ACTIVATE. This actually occurs in Aura environment where
+ // WM_NCACTIVATE is used as a trigger to restore text input focus.
+ // Caveats:
+ // TSF runtime does not increment the reference count of the attached
+ // document manager. See the comment inside the method body for
+ // details.
+ void UpdateAssociateFocus();
+ void ClearAssociateFocus();
+
+ // A triple of document manager, text store and binding cookie between
+ // a context owned by the document manager and the text store. This is a
+ // minimum working set of an editable document in TSF.
+ struct TSFDocument {
+ public:
+ TSFDocument() : cookie(TF_INVALID_COOKIE) {}
+ TSFDocument(const TSFDocument& src)
+ : document_manager(src.document_manager), cookie(src.cookie) {}
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> document_manager;
+ scoped_refptr<TSFTextStore> text_store;
+ DWORD cookie;
+ };
+
+ // Returns a pointer to TSFDocument that is associated with the current
+ // TextInputType of |client_|.
+ TSFDocument* GetAssociatedDocument();
+
+ // An ITfThreadMgr object to be used in focus and document management.
+ Microsoft::WRL::ComPtr<ITfThreadMgr> thread_manager_;
+
+ // A map from TextInputType to an editable document for TSF. We use multiple
+ // TSF documents that have different InputScopes and TSF attributes based on
+ // the TextInputType associated with the target document. For a TextInputType
+ // that is not coverted by this map, a default document, e.g. the document
+ // for TEXT_INPUT_TYPE_TEXT, should be used.
+ // Note that some IMEs don't change their state unless the document focus is
+ // changed. This is why we use multiple documents instead of changing TSF
+ // metadata of a single document on the fly.
+ typedef std::map<TextInputType, TSFDocument> TSFDocumentMap;
+ TSFDocumentMap tsf_document_map_;
+
+ // An identifier of TSF client.
+ TfClientId client_id_ = TF_CLIENTID_NULL;
+
+ // Current focused text input client. Do not free |client_|.
+ TextInputClient* client_ = nullptr;
+
+ // Represents the window that is currently owns text input focus.
+ HWND attached_window_handle_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(TSFBridgeImpl);
+};
+
+TSFBridgeImpl::TSFBridgeImpl() = default;
+
+TSFBridgeImpl::~TSFBridgeImpl() {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ if (!IsInitialized())
+ return;
+ for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
+ it != tsf_document_map_.end(); ++it) {
+ Microsoft::WRL::ComPtr<ITfContext> context;
+ Microsoft::WRL::ComPtr<ITfSource> source;
+ if (it->second.cookie != TF_INVALID_COOKIE &&
+ SUCCEEDED(
+ it->second.document_manager->GetBase(context.GetAddressOf())) &&
+ SUCCEEDED(context.CopyTo(source.GetAddressOf()))) {
+ source->UnadviseSink(it->second.cookie);
+ }
+ }
+ tsf_document_map_.clear();
+
+ client_id_ = TF_CLIENTID_NULL;
+}
+
+bool TSFBridgeImpl::Initialize() {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ if (client_id_ != TF_CLIENTID_NULL) {
+ DVLOG(1) << "Already initialized.";
+ return false;
+ }
+
+ if (FAILED(::CoCreateInstance(CLSID_TF_ThreadMgr, nullptr, CLSCTX_ALL,
+ IID_PPV_ARGS(&thread_manager_)))) {
+ DVLOG(1) << "Failed to create ThreadManager instance.";
+ return false;
+ }
+
+ if (FAILED(thread_manager_->Activate(&client_id_))) {
+ DVLOG(1) << "Failed to activate Thread Manager.";
+ return false;
+ }
+
+ if (!InitializeDocumentMapInternal())
+ return false;
+
+ // Japanese IME expects the default value of this compartment is
+ // TF_SENTENCEMODE_PHRASEPREDICT like IMM32 implementation. This value is
+ // managed per thread, so that it is enough to set this value at once. This
+ // value does not affect other language's IME behaviors.
+ Microsoft::WRL::ComPtr<ITfCompartmentMgr> thread_compartment_manager;
+ if (FAILED(
+ thread_manager_.CopyTo(thread_compartment_manager.GetAddressOf()))) {
+ DVLOG(1) << "Failed to get ITfCompartmentMgr.";
+ return false;
+ }
+
+ Microsoft::WRL::ComPtr<ITfCompartment> sentence_compartment;
+ if (FAILED(thread_compartment_manager->GetCompartment(
+ GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE,
+ sentence_compartment.GetAddressOf()))) {
+ DVLOG(1) << "Failed to get sentence compartment.";
+ return false;
+ }
+
+ base::win::ScopedVariant sentence_variant;
+ sentence_variant.Set(TF_SENTENCEMODE_PHRASEPREDICT);
+ if (FAILED(
+ sentence_compartment->SetValue(client_id_, sentence_variant.ptr()))) {
+ DVLOG(1) << "Failed to change the sentence mode.";
+ return false;
+ }
+
+ return true;
+}
+
+void TSFBridgeImpl::OnTextInputTypeChanged(const TextInputClient* client) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(IsInitialized());
+
+ if (client != client_) {
+ // Called from not focusing client. Do nothing.
+ return;
+ }
+
+ UpdateAssociateFocus();
+
+ TSFDocument* document = GetAssociatedDocument();
+ if (!document)
+ return;
+ thread_manager_->SetFocus(document->document_manager.Get());
+ OnTextLayoutChanged();
+}
+
+void TSFBridgeImpl::OnTextLayoutChanged() {
+ TSFDocument* document = GetAssociatedDocument();
+ if (!document)
+ return;
+ if (!document->text_store)
+ return;
+ document->text_store->SendOnLayoutChange();
+}
+
+bool TSFBridgeImpl::CancelComposition() {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(IsInitialized());
+
+ TSFDocument* document = GetAssociatedDocument();
+ if (!document)
+ return false;
+ if (!document->text_store)
+ return false;
+
+ return document->text_store->CancelComposition();
+}
+
+bool TSFBridgeImpl::ConfirmComposition() {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(IsInitialized());
+
+ TSFDocument* document = GetAssociatedDocument();
+ if (!document)
+ return false;
+ if (!document->text_store)
+ return false;
+
+ return document->text_store->ConfirmComposition();
+}
+
+void TSFBridgeImpl::SetFocusedClient(HWND focused_window,
+ TextInputClient* client) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(client);
+ DCHECK(IsInitialized());
+ if (attached_window_handle_ != focused_window)
+ ClearAssociateFocus();
+ client_ = client;
+ attached_window_handle_ = focused_window;
+
+ for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
+ it != tsf_document_map_.end(); ++it) {
+ if (it->second.text_store.get() == nullptr)
+ continue;
+ it->second.text_store->SetFocusedTextInputClient(focused_window, client);
+ }
+
+ // Synchronize text input type state.
+ OnTextInputTypeChanged(client);
+}
+
+void TSFBridgeImpl::RemoveFocusedClient(TextInputClient* client) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(IsInitialized());
+ if (client_ != client)
+ return;
+ ClearAssociateFocus();
+ client_ = nullptr;
+ attached_window_handle_ = nullptr;
+ for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
+ it != tsf_document_map_.end(); ++it) {
+ if (it->second.text_store.get() == nullptr)
+ continue;
+ it->second.text_store->SetFocusedTextInputClient(nullptr, nullptr);
+ }
+}
+
+TextInputClient* TSFBridgeImpl::GetFocusedTextInputClient() const {
+ return client_;
+}
+
+Microsoft::WRL::ComPtr<ITfThreadMgr> TSFBridgeImpl::GetThreadManager() {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(IsInitialized());
+ return thread_manager_;
+}
+
+bool TSFBridgeImpl::CreateDocumentManager(TSFTextStore* text_store,
+ ITfDocumentMgr** document_manager,
+ ITfContext** context,
+ DWORD* source_cookie) {
+ if (FAILED(thread_manager_->CreateDocumentMgr(document_manager))) {
+ DVLOG(1) << "Failed to create Document Manager.";
+ return false;
+ }
+
+ DWORD edit_cookie = TF_INVALID_EDIT_COOKIE;
+ if (FAILED((*document_manager)
+ ->CreateContext(client_id_, 0,
+ static_cast<ITextStoreACP*>(text_store),
+ context, &edit_cookie))) {
+ DVLOG(1) << "Failed to create Context.";
+ return false;
+ }
+
+ if (FAILED((*document_manager)->Push(*context))) {
+ DVLOG(1) << "Failed to push context.";
+ return false;
+ }
+
+ if (!text_store || !source_cookie)
+ return true;
+
+ Microsoft::WRL::ComPtr<ITfSource> source;
+ if (FAILED((*context)->QueryInterface(IID_PPV_ARGS(&source)))) {
+ DVLOG(1) << "Failed to get source.";
+ return false;
+ }
+
+ if (FAILED(source->AdviseSink(IID_ITfTextEditSink,
+ static_cast<ITfTextEditSink*>(text_store),
+ source_cookie))) {
+ DVLOG(1) << "AdviseSink failed.";
+ return false;
+ }
+
+ if (*source_cookie == TF_INVALID_COOKIE) {
+ DVLOG(1) << "The result of cookie is invalid.";
+ return false;
+ }
+ return true;
+}
+
+bool TSFBridgeImpl::InitializeDocumentMapInternal() {
+ const TextInputType kTextInputTypes[] = {
+ TEXT_INPUT_TYPE_NONE, TEXT_INPUT_TYPE_TEXT,
+ TEXT_INPUT_TYPE_PASSWORD, TEXT_INPUT_TYPE_SEARCH,
+ TEXT_INPUT_TYPE_EMAIL, TEXT_INPUT_TYPE_NUMBER,
+ TEXT_INPUT_TYPE_TELEPHONE, TEXT_INPUT_TYPE_URL,
+ };
+ for (size_t i = 0; i < arraysize(kTextInputTypes); ++i) {
+ const TextInputType input_type = kTextInputTypes[i];
+ Microsoft::WRL::ComPtr<ITfContext> context;
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> document_manager;
+ DWORD cookie = TF_INVALID_COOKIE;
+ const bool use_null_text_store = (input_type == TEXT_INPUT_TYPE_NONE);
+ DWORD* cookie_ptr = use_null_text_store ? nullptr : &cookie;
+ scoped_refptr<TSFTextStore> text_store =
+ use_null_text_store ? nullptr : new TSFTextStore();
+ if (!CreateDocumentManager(text_store.get(),
+ document_manager.GetAddressOf(),
+ context.GetAddressOf(), cookie_ptr))
+ return false;
+ const bool use_disabled_context = (input_type == TEXT_INPUT_TYPE_PASSWORD ||
+ input_type == TEXT_INPUT_TYPE_NONE);
+ if (use_disabled_context && !InitializeDisabledContext(context.Get()))
+ return false;
+ tsf_document_map_[input_type].text_store = text_store;
+ tsf_document_map_[input_type].document_manager = document_manager;
+ tsf_document_map_[input_type].cookie = cookie;
+ }
+ return true;
+}
+
+bool TSFBridgeImpl::InitializeDisabledContext(ITfContext* context) {
+ Microsoft::WRL::ComPtr<ITfCompartmentMgr> compartment_mgr;
+ if (FAILED(context->QueryInterface(IID_PPV_ARGS(&compartment_mgr)))) {
+ DVLOG(1) << "Failed to get CompartmentMgr.";
+ return false;
+ }
+
+ Microsoft::WRL::ComPtr<ITfCompartment> disabled_compartment;
+ if (FAILED(compartment_mgr->GetCompartment(
+ GUID_COMPARTMENT_KEYBOARD_DISABLED,
+ disabled_compartment.GetAddressOf()))) {
+ DVLOG(1) << "Failed to get keyboard disabled compartment.";
+ return false;
+ }
+
+ base::win::ScopedVariant variant;
+ variant.Set(1);
+ if (FAILED(disabled_compartment->SetValue(client_id_, variant.ptr()))) {
+ DVLOG(1) << "Failed to disable the DocumentMgr.";
+ return false;
+ }
+
+ Microsoft::WRL::ComPtr<ITfCompartment> empty_context;
+ if (FAILED(compartment_mgr->GetCompartment(GUID_COMPARTMENT_EMPTYCONTEXT,
+ empty_context.GetAddressOf()))) {
+ DVLOG(1) << "Failed to get empty context compartment.";
+ return false;
+ }
+ base::win::ScopedVariant empty_context_variant;
+ empty_context_variant.Set(static_cast<int32_t>(1));
+ if (FAILED(
+ empty_context->SetValue(client_id_, empty_context_variant.ptr()))) {
+ DVLOG(1) << "Failed to set empty context.";
+ return false;
+ }
+
+ return true;
+}
+
+bool TSFBridgeImpl::IsFocused(ITfDocumentMgr* document_manager) {
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> focused_document_manager;
+ if (FAILED(
+ thread_manager_->GetFocus(focused_document_manager.GetAddressOf())))
+ return false;
+ return focused_document_manager.Get() == document_manager;
+}
+
+bool TSFBridgeImpl::IsInitialized() {
+ return client_id_ != TF_CLIENTID_NULL;
+}
+
+void TSFBridgeImpl::UpdateAssociateFocus() {
+ if (attached_window_handle_ == nullptr)
+ return;
+ TSFDocument* document = GetAssociatedDocument();
+ if (document == nullptr) {
+ ClearAssociateFocus();
+ return;
+ }
+ // NOTE: ITfThreadMgr::AssociateFocus does not increment the ref count of
+ // the document manager to be attached. It is our responsibility to make sure
+ // the attached document manager will not be destroyed while it is attached.
+ // This should be true as long as TSFBridge::Shutdown() is called late phase
+ // of UI thread shutdown.
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> previous_focus;
+ thread_manager_->AssociateFocus(attached_window_handle_,
+ document->document_manager.Get(),
+ previous_focus.GetAddressOf());
+}
+
+void TSFBridgeImpl::ClearAssociateFocus() {
+ if (attached_window_handle_ == nullptr)
+ return;
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> previous_focus;
+ thread_manager_->AssociateFocus(attached_window_handle_, nullptr,
+ previous_focus.GetAddressOf());
+}
+
+TSFBridgeImpl::TSFDocument* TSFBridgeImpl::GetAssociatedDocument() {
+ if (!client_)
+ return nullptr;
+ TSFDocumentMap::iterator it =
+ tsf_document_map_.find(client_->GetTextInputType());
+ if (it == tsf_document_map_.end()) {
+ it = tsf_document_map_.find(TEXT_INPUT_TYPE_TEXT);
+ // This check is necessary because it's possible that we failed to
+ // initialize |tsf_document_map_| and it has no TEXT_INPUT_TYPE_TEXT.
+ if (it == tsf_document_map_.end())
+ return nullptr;
+ }
+ return &it->second;
+}
+
+void Finalize(void* data) {
+ TSFBridgeImpl* delegate = static_cast<TSFBridgeImpl*>(data);
+ delete delegate;
+}
+
+base::ThreadLocalStorage::Slot& TSFBridgeTLS() {
+ static base::NoDestructor<base::ThreadLocalStorage::Slot> tsf_bridge_tls(
+ &Finalize);
+ return *tsf_bridge_tls;
+}
+
+} // namespace
+
+// TsfBridge -----------------------------------------------------------------
+
+TSFBridge::TSFBridge() {}
+
+TSFBridge::~TSFBridge() {}
+
+// static
+void TSFBridge::Initialize() {
+ if (!base::MessageLoopForUI::IsCurrent()) {
+ DVLOG(1) << "Do not use TSFBridge without UI thread.";
+ return;
+ }
+ TSFBridgeImpl* delegate = static_cast<TSFBridgeImpl*>(TSFBridgeTLS().Get());
+ if (delegate)
+ return;
+ // If we aren't supporting TSF early out.
+ if (!base::FeatureList::IsEnabled(features::kTSFImeSupport))
+ return;
+ delegate = new TSFBridgeImpl();
+ TSFBridgeTLS().Set(delegate);
+ delegate->Initialize();
+}
+
+// static
+TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) {
+ if (!base::MessageLoopForUI::IsCurrent()) {
+ DVLOG(1) << "Do not use TSFBridge without UI thread.";
+ return nullptr;
+ }
+ TSFBridge* old_bridge = TSFBridge::GetInstance();
+ TSFBridgeTLS().Set(bridge);
+ return old_bridge;
+}
+
+// static
+void TSFBridge::Shutdown() {
+ if (!base::MessageLoopForUI::IsCurrent()) {
+ DVLOG(1) << "Do not use TSFBridge without UI thread.";
+ }
+ TSFBridgeImpl* delegate = static_cast<TSFBridgeImpl*>(TSFBridgeTLS().Get());
+ TSFBridgeTLS().Set(nullptr);
+ delete delegate;
+}
+
+// static
+TSFBridge* TSFBridge::GetInstance() {
+ if (!base::MessageLoopForUI::IsCurrent()) {
+ DVLOG(1) << "Do not use TSFBridge without UI thread.";
+ return nullptr;
+ }
+ TSFBridgeImpl* delegate = static_cast<TSFBridgeImpl*>(TSFBridgeTLS().Get());
+ DCHECK(delegate) << "Do no call GetInstance before TSFBridge::Initialize.";
+ return delegate;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h
new file mode 100644
index 00000000000..0d24edd6fac
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_bridge.h
@@ -0,0 +1,94 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_WIN_TSF_BRIDGE_H_
+#define UI_BASE_IME_WIN_TSF_BRIDGE_H_
+
+#include <msctf.h>
+#include <windows.h>
+#include <wrl/client.h>
+
+#include "base/macros.h"
+#include "ui/base/ime/ui_base_ime_export.h"
+
+namespace ui {
+class TextInputClient;
+
+// TSFBridge provides high level IME related operations on top of Text Services
+// Framework (TSF). TSFBridge is managed by TLS because TSF related stuff is
+// associated with each thread and not allowed to access across thread boundary.
+// To be consistent with IMM32 behavior, TSFBridge is shared in the same thread.
+// TSFBridge is used by the web content text inputting field, for example
+// DisableIME() should be called if a password field is focused.
+//
+// TSFBridge also manages connectivity between TSFTextStore which is the backend
+// of text inputting and current focused TextInputClient.
+//
+// All methods in this class must be used in UI thread.
+class UI_BASE_IME_EXPORT TSFBridge {
+ public:
+ virtual ~TSFBridge();
+
+ // Returns the thread local TSFBridge instance. Initialize() must be called
+ // first. Do not cache this pointer and use it after TSFBridge Shutdown().
+ static TSFBridge* GetInstance();
+
+ // Sets the thread local instance. Must be called before any calls to
+ // GetInstance().
+ static void Initialize();
+
+ // Injects an alternative TSFBridge such as MockTSFBridge for testing. The
+ // injected object should be released by the caller. This function returns
+ // previous TSFBridge pointer with ownership.
+ static TSFBridge* ReplaceForTesting(TSFBridge* bridge);
+
+ // Destroys the thread local instance.
+ static void Shutdown();
+
+ // Handles TextInputTypeChanged event. RWHVW is responsible for calling this
+ // handler whenever renderer's input text type is changed. Does nothing
+ // unless |client| is focused.
+ virtual void OnTextInputTypeChanged(const TextInputClient* client) = 0;
+
+ // Sends an event to TSF manager that the text layout should be updated.
+ virtual void OnTextLayoutChanged() = 0;
+
+ // Cancels the ongoing composition if exists.
+ // Returns true if there is no composition.
+ // Returns false if an edit session is on-going.
+ // Returns false if an error occures.
+ virtual bool CancelComposition() = 0;
+
+ // Confirms the ongoing composition if exists.
+ // Returns true if there is no composition.
+ // Returns false if an edit session is on-going.
+ // Returns false if an error occures.
+ virtual bool ConfirmComposition() = 0;
+
+ // Sets currently focused TextInputClient.
+ // Caller must free |client|.
+ virtual void SetFocusedClient(HWND focused_window,
+ TextInputClient* client) = 0;
+
+ // Removes currently focused TextInputClient.
+ // Caller must free |client|.
+ virtual void RemoveFocusedClient(TextInputClient* client) = 0;
+
+ // Obtains current thread manager.
+ virtual Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() = 0;
+
+ // Returns the focused text input client.
+ virtual TextInputClient* GetFocusedTextInputClient() const = 0;
+
+ protected:
+ // Uses GetInstance() instead.
+ TSFBridge();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TSFBridge);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_TSF_BRIDGE_H_
diff --git a/chromium/ui/base/ime/win/tsf_event_router.cc b/chromium/ui/base/ime/win/tsf_event_router.cc
new file mode 100644
index 00000000000..a67ad224f7c
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_event_router.cc
@@ -0,0 +1,296 @@
+// 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/win/tsf_event_router.h"
+
+#include <msctf.h>
+#include <wrl/client.h>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "ui/base/win/atl_module.h"
+#include "ui/gfx/range/range.h"
+
+namespace ui {
+
+// TSFEventRouter::Delegate ------------------------------------
+
+// The implementation class of ITfUIElementSink, whose member functions will be
+// called back by TSF when the UI element status is changed, for example when
+// the candidate window is opened or closed. This class also implements
+// ITfTextEditSink, whose member function is called back by TSF when the text
+// editting session is finished.
+class ATL_NO_VTABLE TSFEventRouter::Delegate
+ : public ATL::CComObjectRootEx<CComSingleThreadModel>,
+ public ITfUIElementSink,
+ public ITfTextEditSink {
+ public:
+ BEGIN_COM_MAP(Delegate)
+ COM_INTERFACE_ENTRY(ITfUIElementSink)
+ COM_INTERFACE_ENTRY(ITfTextEditSink)
+ END_COM_MAP()
+
+ Delegate();
+ ~Delegate();
+
+ // ITfTextEditSink:
+ STDMETHOD(OnEndEdit)
+ (ITfContext* context,
+ TfEditCookie read_only_cookie,
+ ITfEditRecord* edit_record) override;
+
+ // ITfUiElementSink:
+ STDMETHOD(BeginUIElement)(DWORD element_id, BOOL* is_show) override;
+ STDMETHOD(UpdateUIElement)(DWORD element_id) override;
+ STDMETHOD(EndUIElement)(DWORD element_id) override;
+
+ // Sets |thread_manager| to be monitored. |thread_manager| can be nullptr.
+ void SetManager(ITfThreadMgr* thread_manager);
+
+ // Returns true if the IME is composing text.
+ bool IsImeComposing();
+
+ // Sets |router| to be forwarded TSF-related events.
+ void SetRouter(TSFEventRouter* router);
+
+ private:
+ // Returns current composition range. Returns gfx::Range::InvalidRange if
+ // there is no composition.
+ static gfx::Range GetCompositionRange(ITfContext* context);
+
+ // Returns true if the given |element_id| represents the candidate window.
+ bool IsCandidateWindowInternal(DWORD element_id);
+
+ // A context associated with this class.
+ Microsoft::WRL::ComPtr<ITfContext> context_;
+
+ // The ITfSource associated with |context_|.
+ Microsoft::WRL::ComPtr<ITfSource> context_source_;
+
+ // The cookie for |context_source_|.
+ DWORD context_source_cookie_;
+
+ // A UIElementMgr associated with this class.
+ Microsoft::WRL::ComPtr<ITfUIElementMgr> ui_element_manager_;
+
+ // The ITfSouce associated with |ui_element_manager_|.
+ Microsoft::WRL::ComPtr<ITfSource> ui_source_;
+
+ // The set of currently opened candidate window ids.
+ std::set<DWORD> open_candidate_window_ids_;
+
+ // The cookie for |ui_source_|.
+ DWORD ui_source_cookie_ = TF_INVALID_COOKIE;
+
+ TSFEventRouter* router_ = nullptr;
+ gfx::Range previous_composition_range_;
+
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+};
+
+TSFEventRouter::Delegate::Delegate()
+ : previous_composition_range_(gfx::Range::InvalidRange()) {}
+
+TSFEventRouter::Delegate::~Delegate() = default;
+
+void TSFEventRouter::Delegate::SetRouter(TSFEventRouter* router) {
+ router_ = router;
+}
+
+STDMETHODIMP TSFEventRouter::Delegate::OnEndEdit(ITfContext* context,
+ TfEditCookie read_only_cookie,
+ ITfEditRecord* edit_record) {
+ if (!edit_record || !context)
+ return E_INVALIDARG;
+ if (!router_)
+ return S_OK;
+
+ // |edit_record| can be used to obtain updated ranges in terms of text
+ // contents and/or text attributes. Here we are interested only in text update
+ // so we use TF_GTP_INCL_TEXT and check if there is any range which contains
+ // updated text.
+ Microsoft::WRL::ComPtr<IEnumTfRanges> ranges;
+ if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, nullptr,
+ 0, ranges.GetAddressOf())))
+ return S_OK; // Don't care about failures.
+
+ ULONG fetched_count = 0;
+ Microsoft::WRL::ComPtr<ITfRange> range;
+ if (FAILED(ranges->Next(1, range.GetAddressOf(), &fetched_count)))
+ return S_OK; // Don't care about failures.
+
+ const gfx::Range composition_range = GetCompositionRange(context);
+
+ if (!previous_composition_range_.IsValid() && composition_range.IsValid())
+ router_->OnTSFStartComposition();
+
+ // |fetched_count| != 0 means there is at least one range that contains
+ // updated text.
+ if (fetched_count != 0)
+ router_->OnTextUpdated(composition_range);
+
+ if (previous_composition_range_.IsValid() && !composition_range.IsValid())
+ router_->OnTSFEndComposition();
+
+ previous_composition_range_ = composition_range;
+ return S_OK;
+}
+
+STDMETHODIMP TSFEventRouter::Delegate::BeginUIElement(DWORD element_id,
+ BOOL* is_show) {
+ if (is_show)
+ *is_show = TRUE; // Without this the UI element will not be shown.
+
+ if (!IsCandidateWindowInternal(element_id))
+ return S_OK;
+
+ std::pair<std::set<DWORD>::iterator, bool> insert_result =
+ open_candidate_window_ids_.insert(element_id);
+ // Don't call if |router_| is null or |element_id| is already handled.
+ if (router_ && insert_result.second)
+ router_->OnCandidateWindowCountChanged(open_candidate_window_ids_.size());
+
+ return S_OK;
+}
+
+STDMETHODIMP TSFEventRouter::Delegate::UpdateUIElement(DWORD element_id) {
+ return S_OK;
+}
+
+STDMETHODIMP TSFEventRouter::Delegate::EndUIElement(DWORD element_id) {
+ if ((open_candidate_window_ids_.erase(element_id) != 0) && router_)
+ router_->OnCandidateWindowCountChanged(open_candidate_window_ids_.size());
+ return S_OK;
+}
+
+void TSFEventRouter::Delegate::SetManager(ITfThreadMgr* thread_manager) {
+ context_.Reset();
+
+ if (context_source_) {
+ context_source_->UnadviseSink(context_source_cookie_);
+ context_source_.Reset();
+ }
+ context_source_cookie_ = TF_INVALID_COOKIE;
+
+ ui_element_manager_.Reset();
+ if (ui_source_) {
+ ui_source_->UnadviseSink(ui_source_cookie_);
+ ui_source_.Reset();
+ }
+ ui_source_cookie_ = TF_INVALID_COOKIE;
+
+ if (!thread_manager)
+ return;
+
+ Microsoft::WRL::ComPtr<ITfDocumentMgr> document_manager;
+ if (FAILED(thread_manager->GetFocus(document_manager.GetAddressOf())) ||
+ !document_manager.Get() ||
+ FAILED(document_manager->GetBase(context_.GetAddressOf())) ||
+ FAILED(context_.CopyTo(context_source_.GetAddressOf())))
+ return;
+ context_source_->AdviseSink(IID_ITfTextEditSink,
+ static_cast<ITfTextEditSink*>(this),
+ &context_source_cookie_);
+
+ if (FAILED(
+ thread_manager->QueryInterface(IID_PPV_ARGS(&ui_element_manager_))) ||
+ FAILED(ui_element_manager_.CopyTo(ui_source_.GetAddressOf())))
+ return;
+ ui_source_->AdviseSink(IID_ITfUIElementSink,
+ static_cast<ITfUIElementSink*>(this),
+ &ui_source_cookie_);
+}
+
+bool TSFEventRouter::Delegate::IsImeComposing() {
+ return context_ && GetCompositionRange(context_.Get()).IsValid();
+}
+
+// static
+gfx::Range TSFEventRouter::Delegate::GetCompositionRange(ITfContext* context) {
+ DCHECK(context);
+ Microsoft::WRL::ComPtr<ITfContextComposition> context_composition;
+ if (FAILED(context->QueryInterface(IID_PPV_ARGS(&context_composition))))
+ return gfx::Range::InvalidRange();
+ Microsoft::WRL::ComPtr<IEnumITfCompositionView> enum_composition_view;
+ if (FAILED(context_composition->EnumCompositions(
+ enum_composition_view.GetAddressOf())))
+ return gfx::Range::InvalidRange();
+ Microsoft::WRL::ComPtr<ITfCompositionView> composition_view;
+ if (enum_composition_view->Next(1, composition_view.GetAddressOf(),
+ nullptr) != S_OK)
+ return gfx::Range::InvalidRange();
+
+ Microsoft::WRL::ComPtr<ITfRange> range;
+ if (FAILED(composition_view->GetRange(range.GetAddressOf())))
+ return gfx::Range::InvalidRange();
+
+ Microsoft::WRL::ComPtr<ITfRangeACP> range_acp;
+ if (FAILED(range.CopyTo(range_acp.GetAddressOf())))
+ return gfx::Range::InvalidRange();
+
+ LONG start = 0;
+ LONG length = 0;
+ if (FAILED(range_acp->GetExtent(&start, &length)))
+ return gfx::Range::InvalidRange();
+
+ return gfx::Range(start, start + length);
+}
+
+bool TSFEventRouter::Delegate::IsCandidateWindowInternal(DWORD element_id) {
+ DCHECK(ui_element_manager_.Get());
+ Microsoft::WRL::ComPtr<ITfUIElement> ui_element;
+ if (FAILED(ui_element_manager_->GetUIElement(element_id,
+ ui_element.GetAddressOf())))
+ return false;
+ Microsoft::WRL::ComPtr<ITfCandidateListUIElement> candidate_list_ui_element;
+ return SUCCEEDED(ui_element.CopyTo(candidate_list_ui_element.GetAddressOf()));
+}
+
+// TSFEventRouter ------------------------------------------------------------
+
+TSFEventRouter::TSFEventRouter(TSFEventRouterObserver* observer)
+ : observer_(observer) {
+ DCHECK(observer_);
+ CComObject<Delegate>* delegate;
+ ui::win::CreateATLModuleIfNeeded();
+ if (SUCCEEDED(CComObject<Delegate>::CreateInstance(&delegate))) {
+ delegate->AddRef();
+ delegate_.Attach(delegate);
+ delegate_->SetRouter(this);
+ }
+}
+
+TSFEventRouter::~TSFEventRouter() {
+ if (delegate_) {
+ delegate_->SetManager(nullptr);
+ delegate_->SetRouter(nullptr);
+ }
+}
+
+bool TSFEventRouter::IsImeComposing() {
+ return delegate_->IsImeComposing();
+}
+
+void TSFEventRouter::OnCandidateWindowCountChanged(size_t window_count) {
+ observer_->OnCandidateWindowCountChanged(window_count);
+}
+
+void TSFEventRouter::OnTSFStartComposition() {
+ observer_->OnTSFStartComposition();
+}
+
+void TSFEventRouter::OnTextUpdated(const gfx::Range& composition_range) {
+ observer_->OnTextUpdated(composition_range);
+}
+
+void TSFEventRouter::OnTSFEndComposition() {
+ observer_->OnTSFEndComposition();
+}
+
+void TSFEventRouter::SetManager(ITfThreadMgr* thread_manager) {
+ delegate_->SetManager(thread_manager);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_event_router.h b/chromium/ui/base/ime/win/tsf_event_router.h
new file mode 100644
index 00000000000..d094e1ba9b1
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_event_router.h
@@ -0,0 +1,78 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_
+#define UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <msctf.h>
+
+#include <set>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/base/ime/ui_base_ime_export.h"
+#include "ui/gfx/range/range.h"
+
+namespace ui {
+
+class TSFEventRouterObserver {
+ public:
+ TSFEventRouterObserver() {}
+
+ // Called when the number of currently opened candidate windows changes.
+ virtual void OnCandidateWindowCountChanged(size_t window_count) {}
+
+ // Called when a composition is started.
+ virtual void OnTSFStartComposition() {}
+
+ // Called when the text contents are updated. If there is no composition,
+ // gfx::Range::InvalidRange is passed to |composition_range|.
+ virtual void OnTextUpdated(const gfx::Range& composition_range) {}
+
+ // Called when a composition is terminated.
+ virtual void OnTSFEndComposition() {}
+
+ protected:
+ virtual ~TSFEventRouterObserver() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TSFEventRouterObserver);
+};
+
+// This class monitors TSF related events and forwards them to given
+// |observer|.
+class UI_BASE_IME_EXPORT TSFEventRouter {
+ public:
+ // Do not pass NULL to |observer|.
+ explicit TSFEventRouter(TSFEventRouterObserver* observer);
+ virtual ~TSFEventRouter();
+
+ // Returns true if the IME is composing text.
+ bool IsImeComposing();
+
+ // Callbacks from the TSFEventRouterDelegate:
+ void OnCandidateWindowCountChanged(size_t window_count);
+ void OnTSFStartComposition();
+ void OnTextUpdated(const gfx::Range& composition_range);
+ void OnTSFEndComposition();
+
+ // Sets |thread_manager| to be monitored. |thread_manager| can be NULL.
+ void SetManager(ITfThreadMgr* thread_manager);
+
+ private:
+ class Delegate;
+
+ CComPtr<Delegate> delegate_;
+
+ TSFEventRouterObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(TSFEventRouter);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_TSF_EVENT_ROUTER_H_
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
new file mode 100644
index 00000000000..6fb766ded9e
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_text_store.cc
@@ -0,0 +1,925 @@
+// 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.
+
+#define INITGUID // required for GUID_PROP_INPUTSCOPE
+#include "ui/base/ime/win/tsf_text_store.h"
+
+#include <InputScope.h>
+#include <OleCtl.h>
+#include <wrl/client.h>
+
+#include <algorithm>
+
+#include "base/win/scoped_variant.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/win/tsf_input_scope.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ui {
+namespace {
+
+// We support only one view.
+const TsViewCookie kViewCookie = 1;
+
+} // namespace
+
+TSFTextStore::TSFTextStore() {
+ if (FAILED(::CoCreateInstance(CLSID_TF_CategoryMgr, nullptr, CLSCTX_ALL,
+ IID_PPV_ARGS(&category_manager_)))) {
+ LOG(FATAL) << "Failed to initialize CategoryMgr.";
+ return;
+ }
+ if (FAILED(::CoCreateInstance(CLSID_TF_DisplayAttributeMgr, nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(&display_attribute_manager_)))) {
+ LOG(FATAL) << "Failed to initialize DisplayAttributeMgr.";
+ return;
+ }
+}
+
+TSFTextStore::~TSFTextStore() {}
+
+ULONG STDMETHODCALLTYPE TSFTextStore::AddRef() {
+ return InterlockedIncrement(&ref_count_);
+}
+
+ULONG STDMETHODCALLTYPE TSFTextStore::Release() {
+ const LONG count = InterlockedDecrement(&ref_count_);
+ if (!count) {
+ delete this;
+ return 0;
+ }
+ return static_cast<ULONG>(count);
+}
+
+STDMETHODIMP TSFTextStore::QueryInterface(REFIID iid, void** result) {
+ if (iid == IID_IUnknown || iid == IID_ITextStoreACP) {
+ *result = static_cast<ITextStoreACP*>(this);
+ } else if (iid == IID_ITfContextOwnerCompositionSink) {
+ *result = static_cast<ITfContextOwnerCompositionSink*>(this);
+ } else if (iid == IID_ITfTextEditSink) {
+ *result = static_cast<ITfTextEditSink*>(this);
+ } else {
+ *result = nullptr;
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::AdviseSink(REFIID iid,
+ IUnknown* unknown,
+ DWORD mask) {
+ if (!IsEqualGUID(iid, IID_ITextStoreACPSink))
+ return E_INVALIDARG;
+ if (text_store_acp_sink_) {
+ if (text_store_acp_sink_.Get() == unknown) {
+ text_store_acp_sink_mask_ = mask;
+ return S_OK;
+ } else {
+ return CONNECT_E_ADVISELIMIT;
+ }
+ }
+ if (FAILED(unknown->QueryInterface(IID_PPV_ARGS(&text_store_acp_sink_))))
+ return E_UNEXPECTED;
+ text_store_acp_sink_mask_ = mask;
+
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::FindNextAttrTransition(
+ LONG acp_start,
+ LONG acp_halt,
+ ULONG num_filter_attributes,
+ const TS_ATTRID* filter_attributes,
+ DWORD flags,
+ LONG* acp_next,
+ BOOL* found,
+ LONG* found_offset) {
+ if (!acp_next || !found || !found_offset)
+ return E_INVALIDARG;
+ // We don't support any attributes.
+ // So we always return "not found".
+ *acp_next = 0;
+ *found = FALSE;
+ *found_offset = 0;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetACPFromPoint(TsViewCookie view_cookie,
+ const POINT* point,
+ DWORD flags,
+ LONG* acp) {
+ NOTIMPLEMENTED();
+ if (view_cookie != kViewCookie)
+ return E_INVALIDARG;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP TSFTextStore::GetActiveView(TsViewCookie* view_cookie) {
+ if (!view_cookie)
+ return E_INVALIDARG;
+ // We support only one view.
+ *view_cookie = kViewCookie;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetEmbedded(LONG acp_pos,
+ REFGUID service,
+ REFIID iid,
+ IUnknown** unknown) {
+ // We don't support any embedded objects.
+ NOTIMPLEMENTED();
+ if (!unknown)
+ return E_INVALIDARG;
+ *unknown = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP TSFTextStore::GetEndACP(LONG* acp) {
+ if (!acp)
+ return E_INVALIDARG;
+ if (!HasReadLock())
+ return TS_E_NOLOCK;
+ *acp = string_buffer_.size();
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetFormattedText(LONG acp_start,
+ LONG acp_end,
+ IDataObject** data_object) {
+ NOTIMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) {
+ if (view_cookie != kViewCookie)
+ return E_INVALIDARG;
+ if (!rect)
+ return E_INVALIDARG;
+
+ // {0, 0, 0, 0} means that the document rect is not currently displayed.
+ SetRect(rect, 0, 0, 0, 0);
+
+ if (!IsWindow(window_handle_))
+ return E_FAIL;
+
+ // Currently ui::TextInputClient does not expose the document rect. So use
+ // the Win32 client rectangle instead.
+ // TODO(yukawa): Upgrade TextInputClient so that the client can retrieve the
+ // document rectangle.
+ RECT client_rect = {};
+ if (!GetClientRect(window_handle_, &client_rect))
+ return E_FAIL;
+ POINT left_top = {client_rect.left, client_rect.top};
+ POINT right_bottom = {client_rect.right, client_rect.bottom};
+ if (!ClientToScreen(window_handle_, &left_top))
+ return E_FAIL;
+ if (!ClientToScreen(window_handle_, &right_bottom))
+ return E_FAIL;
+
+ rect->left = left_top.x;
+ rect->top = left_top.y;
+ rect->right = right_bottom.x;
+ rect->bottom = right_bottom.y;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetSelection(ULONG selection_index,
+ ULONG selection_buffer_size,
+ TS_SELECTION_ACP* selection_buffer,
+ ULONG* fetched_count) {
+ if (!selection_buffer)
+ return E_INVALIDARG;
+ if (!fetched_count)
+ return E_INVALIDARG;
+ if (!HasReadLock())
+ return TS_E_NOLOCK;
+ *fetched_count = 0;
+ if ((selection_buffer_size > 0) &&
+ ((selection_index == 0) || (selection_index == TS_DEFAULT_SELECTION))) {
+ selection_buffer[0].acpStart = selection_.start();
+ selection_buffer[0].acpEnd = selection_.end();
+ selection_buffer[0].style.ase = TS_AE_END;
+ selection_buffer[0].style.fInterimChar = FALSE;
+ *fetched_count = 1;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetStatus(TS_STATUS* status) {
+ if (!status)
+ return E_INVALIDARG;
+
+ status->dwDynamicFlags = 0;
+ // We use transitory contexts and we don't support hidden text.
+ // TODO(dtapuska): Remove TS_SS_TRANSITORY it was added to fix
+ // https://crbug.com/148355
+ status->dwStaticFlags = TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT;
+
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetText(LONG acp_start,
+ LONG acp_end,
+ wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ ULONG* text_buffer_copied,
+ TS_RUNINFO* run_info_buffer,
+ ULONG run_info_buffer_size,
+ ULONG* run_info_buffer_copied,
+ LONG* next_acp) {
+ if (!text_buffer_copied || !run_info_buffer_copied)
+ return E_INVALIDARG;
+ if (!text_buffer && text_buffer_size != 0)
+ return E_INVALIDARG;
+ if (!run_info_buffer && run_info_buffer_size != 0)
+ return E_INVALIDARG;
+ if (!next_acp)
+ return E_INVALIDARG;
+ if (!HasReadLock())
+ return TF_E_NOLOCK;
+ const LONG string_buffer_size = string_buffer_.size();
+ if (acp_end == -1)
+ acp_end = string_buffer_size;
+ if (!((0 <= acp_start) && (acp_start <= acp_end) &&
+ (acp_end <= string_buffer_size))) {
+ return TF_E_INVALIDPOS;
+ }
+ acp_end = std::min(acp_end, acp_start + static_cast<LONG>(text_buffer_size));
+ *text_buffer_copied = acp_end - acp_start;
+
+ const base::string16& result =
+ string_buffer_.substr(acp_start, *text_buffer_copied);
+ for (size_t i = 0; i < result.size(); ++i) {
+ text_buffer[i] = result[i];
+ }
+
+ if (run_info_buffer_size) {
+ run_info_buffer[0].uCount = *text_buffer_copied;
+ run_info_buffer[0].type = TS_RT_PLAIN;
+ *run_info_buffer_copied = 1;
+ }
+
+ *next_acp = acp_end;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie,
+ LONG acp_start,
+ LONG acp_end,
+ RECT* rect,
+ BOOL* clipped) {
+ if (!rect || !clipped)
+ return E_INVALIDARG;
+ if (!text_input_client_)
+ return E_UNEXPECTED;
+ if (view_cookie != kViewCookie)
+ return E_INVALIDARG;
+ if (!HasReadLock())
+ return TS_E_NOLOCK;
+ if (!((static_cast<LONG>(committed_size_) <= acp_start) &&
+ (acp_start <= acp_end) &&
+ (acp_end <= static_cast<LONG>(string_buffer_.size())))) {
+ return TS_E_INVALIDPOS;
+ }
+
+ // According to a behavior of notepad.exe and wordpad.exe, top left corner of
+ // rect indicates a first character's one, and bottom right corner of rect
+ // indicates a last character's one.
+ // We use RECT instead of gfx::Rect since left position may be bigger than
+ // right position when composition has multiple lines.
+ RECT result;
+ gfx::Rect tmp_rect;
+ const uint32_t start_pos = acp_start - committed_size_;
+ const uint32_t end_pos = acp_end - committed_size_;
+
+ if (start_pos == end_pos) {
+ // According to MSDN document, if |acp_start| and |acp_end| are equal it is
+ // OK to just return E_INVALIDARG.
+ // http://msdn.microsoft.com/en-us/library/ms538435
+ // But when using Pinin IME of Windows 8, this method is called with the
+ // equal values of |acp_start| and |acp_end|. So we handle this condition.
+ if (start_pos == 0) {
+ if (text_input_client_->GetCompositionCharacterBounds(0, &tmp_rect)) {
+ tmp_rect.set_width(0);
+ result = tmp_rect.ToRECT();
+ } else if (string_buffer_.size() == committed_size_) {
+ result = text_input_client_->GetCaretBounds().ToRECT();
+ } else {
+ return TS_E_NOLAYOUT;
+ }
+ } else if (text_input_client_->GetCompositionCharacterBounds(start_pos - 1,
+ &tmp_rect)) {
+ result.left = tmp_rect.right();
+ result.right = tmp_rect.right();
+ result.top = tmp_rect.y();
+ result.bottom = tmp_rect.bottom();
+ } else {
+ return TS_E_NOLAYOUT;
+ }
+ } else {
+ if (text_input_client_->GetCompositionCharacterBounds(start_pos,
+ &tmp_rect)) {
+ result.left = tmp_rect.x();
+ result.top = tmp_rect.y();
+ result.right = tmp_rect.right();
+ result.bottom = tmp_rect.bottom();
+ if (text_input_client_->GetCompositionCharacterBounds(end_pos - 1,
+ &tmp_rect)) {
+ result.right = tmp_rect.right();
+ result.bottom = tmp_rect.bottom();
+ } else {
+ // We may not be able to get the last character bounds, so we use the
+ // first character bounds instead of returning TS_E_NOLAYOUT.
+ }
+ } else {
+ // Hack for PPAPI flash. PPAPI flash does not support GetCaretBounds, so
+ // it's better to return previous caret rectangle instead.
+ // TODO(nona, kinaba): Remove this hack.
+ if (start_pos == 0) {
+ result = text_input_client_->GetCaretBounds().ToRECT();
+ } else {
+ return TS_E_NOLAYOUT;
+ }
+ }
+ }
+
+ *rect = result;
+ *clipped = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::GetWnd(TsViewCookie view_cookie,
+ HWND* window_handle) {
+ if (!window_handle)
+ return E_INVALIDARG;
+ if (view_cookie != kViewCookie)
+ return E_INVALIDARG;
+ *window_handle = window_handle_;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::InsertEmbedded(DWORD flags,
+ LONG acp_start,
+ LONG acp_end,
+ IDataObject* data_object,
+ TS_TEXTCHANGE* change) {
+ // We don't support any embedded objects.
+ NOTIMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP TSFTextStore::InsertEmbeddedAtSelection(DWORD flags,
+ IDataObject* data_object,
+ LONG* acp_start,
+ LONG* acp_end,
+ TS_TEXTCHANGE* change) {
+ // We don't support any embedded objects.
+ NOTIMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP TSFTextStore::InsertTextAtSelection(DWORD flags,
+ const wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ LONG* acp_start,
+ LONG* acp_end,
+ TS_TEXTCHANGE* text_change) {
+ const LONG start_pos = selection_.start();
+ const LONG end_pos = selection_.end();
+ const LONG new_end_pos = start_pos + text_buffer_size;
+
+ if (flags & TS_IAS_QUERYONLY) {
+ if (!HasReadLock())
+ return TS_E_NOLOCK;
+ if (acp_start)
+ *acp_start = start_pos;
+ if (acp_end) {
+ *acp_end = end_pos;
+ }
+ return S_OK;
+ }
+
+ if (!HasReadWriteLock())
+ return TS_E_NOLOCK;
+ if (!text_buffer)
+ return E_INVALIDARG;
+
+ DCHECK_LE(start_pos, end_pos);
+ string_buffer_ = string_buffer_.substr(0, start_pos) +
+ base::string16(text_buffer, text_buffer + text_buffer_size) +
+ string_buffer_.substr(end_pos);
+ if (acp_start)
+ *acp_start = start_pos;
+ if (acp_end)
+ *acp_end = new_end_pos;
+ if (text_change) {
+ text_change->acpStart = start_pos;
+ text_change->acpOldEnd = end_pos;
+ text_change->acpNewEnd = new_end_pos;
+ }
+ selection_.set_start(start_pos);
+ selection_.set_end(new_end_pos);
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::QueryInsert(LONG acp_test_start,
+ LONG acp_test_end,
+ ULONG text_size,
+ LONG* acp_result_start,
+ LONG* acp_result_end) {
+ if (!acp_result_start || !acp_result_end || acp_test_start > acp_test_end)
+ return E_INVALIDARG;
+ const LONG committed_size = static_cast<LONG>(committed_size_);
+ const LONG buffer_size = static_cast<LONG>(string_buffer_.size());
+ *acp_result_start =
+ std::min(std::max(committed_size, acp_test_start), buffer_size);
+ *acp_result_end =
+ std::min(std::max(committed_size, acp_test_end), buffer_size);
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::QueryInsertEmbedded(const GUID* service,
+ const FORMATETC* format,
+ BOOL* insertable) {
+ if (!format)
+ return E_INVALIDARG;
+ // We don't support any embedded objects.
+ if (insertable)
+ *insertable = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::RequestAttrsAtPosition(
+ LONG acp_pos,
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer,
+ DWORD flags) {
+ // We don't support any document attributes.
+ // This method just returns S_OK, and the subsequently called
+ // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::RequestAttrsTransitioningAtPosition(
+ LONG acp_pos,
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer,
+ DWORD flags) {
+ // We don't support any document attributes.
+ // This method just returns S_OK, and the subsequently called
+ // RetrieveRequestedAttrs() returns 0 as the number of supported attributes.
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
+ if (!text_store_acp_sink_.Get())
+ return E_FAIL;
+ if (!result)
+ return E_INVALIDARG;
+
+ if (current_lock_type_ != 0) {
+ if (lock_flags & TS_LF_SYNC) {
+ // Can't lock synchronously.
+ *result = TS_E_SYNCHRONOUS;
+ return S_OK;
+ }
+ // Queue the lock request.
+ lock_queue_.push_back(lock_flags & TS_LF_READWRITE);
+ *result = TS_S_ASYNC;
+ return S_OK;
+ }
+
+ // Lock
+ current_lock_type_ = (lock_flags & TS_LF_READWRITE);
+
+ edit_flag_ = false;
+ const size_t last_committed_size = committed_size_;
+
+ // Grant the lock.
+ *result = text_store_acp_sink_->OnLockGranted(current_lock_type_);
+
+ // Unlock
+ current_lock_type_ = 0;
+
+ // Handles the pending lock requests.
+ while (!lock_queue_.empty()) {
+ current_lock_type_ = lock_queue_.front();
+ lock_queue_.pop_front();
+ text_store_acp_sink_->OnLockGranted(current_lock_type_);
+ current_lock_type_ = 0;
+ }
+
+ if (!edit_flag_) {
+ return S_OK;
+ }
+
+ // If the text store is edited in OnLockGranted(), we may need to call
+ // TextInputClient::InsertText() or TextInputClient::SetCompositionText().
+ const size_t new_committed_size = committed_size_;
+ const base::string16& new_committed_string = string_buffer_.substr(
+ last_committed_size, new_committed_size - last_committed_size);
+ const base::string16& composition_string =
+ string_buffer_.substr(new_committed_size);
+
+ // If there is new committed string, calls TextInputClient::InsertText().
+ if ((!new_committed_string.empty()) && text_input_client_) {
+ text_input_client_->InsertText(new_committed_string);
+ }
+
+ // Calls TextInputClient::SetCompositionText().
+ CompositionText composition_text;
+ composition_text.text = composition_string;
+ composition_text.ime_text_spans = text_spans_;
+ // Adjusts the offset.
+ for (size_t i = 0; i < composition_text.ime_text_spans.size(); ++i) {
+ composition_text.ime_text_spans[i].start_offset -= new_committed_size;
+ composition_text.ime_text_spans[i].end_offset -= new_committed_size;
+ }
+ if (selection_.start() < new_committed_size) {
+ composition_text.selection.set_start(0);
+ } else {
+ composition_text.selection.set_start(selection_.start() -
+ new_committed_size);
+ }
+ if (selection_.end() < new_committed_size) {
+ composition_text.selection.set_end(0);
+ } else {
+ composition_text.selection.set_end(selection_.end() - new_committed_size);
+ }
+ if (text_input_client_)
+ text_input_client_->SetCompositionText(composition_text);
+
+ // If there is no composition string, clear the text store status.
+ // And call OnSelectionChange(), OnLayoutChange(), and OnTextChange().
+ if ((composition_string.empty()) && (new_committed_size != 0)) {
+ string_buffer_.clear();
+ committed_size_ = 0;
+ selection_.set_start(0);
+ selection_.set_end(0);
+ if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
+ text_store_acp_sink_->OnSelectionChange();
+ if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+ if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
+ TS_TEXTCHANGE textChange;
+ textChange.acpStart = 0;
+ textChange.acpOldEnd = new_committed_size;
+ textChange.acpNewEnd = 0;
+ text_store_acp_sink_->OnTextChange(0, &textChange);
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::RequestSupportedAttrs(
+ DWORD /* flags */, // Seems that we should ignore this.
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer) {
+ if (!attribute_buffer)
+ return E_INVALIDARG;
+ if (!text_input_client_)
+ return E_FAIL;
+ // We support only input scope attribute.
+ for (size_t i = 0; i < attribute_buffer_size; ++i) {
+ if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i]))
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs(
+ ULONG attribute_buffer_size,
+ TS_ATTRVAL* attribute_buffer,
+ ULONG* attribute_buffer_copied) {
+ if (!attribute_buffer_copied)
+ return E_INVALIDARG;
+ if (!attribute_buffer)
+ return E_INVALIDARG;
+ if (!text_input_client_)
+ return E_UNEXPECTED;
+ // We support only input scope attribute.
+ *attribute_buffer_copied = 0;
+ if (attribute_buffer_size == 0)
+ return S_OK;
+
+ attribute_buffer[0].dwOverlapId = 0;
+ attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE;
+ attribute_buffer[0].varValue.vt = VT_UNKNOWN;
+ attribute_buffer[0].varValue.punkVal =
+ tsf_inputscope::CreateInputScope(text_input_client_->GetTextInputType(),
+ text_input_client_->GetTextInputMode());
+ attribute_buffer[0].varValue.punkVal->AddRef();
+ *attribute_buffer_copied = 1;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::SetSelection(
+ ULONG selection_buffer_size,
+ const TS_SELECTION_ACP* selection_buffer) {
+ if (!HasReadWriteLock())
+ return TF_E_NOLOCK;
+ if (selection_buffer_size > 0) {
+ const LONG start_pos = selection_buffer[0].acpStart;
+ const LONG end_pos = selection_buffer[0].acpEnd;
+ if (!((static_cast<LONG>(committed_size_) <= start_pos) &&
+ (start_pos <= end_pos) &&
+ (end_pos <= static_cast<LONG>(string_buffer_.size())))) {
+ return TF_E_INVALIDPOS;
+ }
+ selection_.set_start(start_pos);
+ selection_.set_end(end_pos);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::SetText(DWORD flags,
+ LONG acp_start,
+ LONG acp_end,
+ const wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ TS_TEXTCHANGE* text_change) {
+ if (!HasReadWriteLock())
+ return TS_E_NOLOCK;
+ if (!((static_cast<LONG>(committed_size_) <= acp_start) &&
+ (acp_start <= acp_end) &&
+ (acp_end <= static_cast<LONG>(string_buffer_.size())))) {
+ return TS_E_INVALIDPOS;
+ }
+
+ TS_SELECTION_ACP selection;
+ selection.acpStart = acp_start;
+ selection.acpEnd = acp_end;
+ selection.style.ase = TS_AE_NONE;
+ selection.style.fInterimChar = 0;
+
+ HRESULT ret;
+ ret = SetSelection(1, &selection);
+ if (ret != S_OK)
+ return ret;
+
+ TS_TEXTCHANGE change;
+ ret = InsertTextAtSelection(0, text_buffer, text_buffer_size, &acp_start,
+ &acp_end, &change);
+ if (ret != S_OK)
+ return ret;
+
+ if (text_change)
+ *text_change = change;
+
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::UnadviseSink(IUnknown* unknown) {
+ if (text_store_acp_sink_.Get() != unknown)
+ return CONNECT_E_NOCONNECTION;
+ text_store_acp_sink_.Reset();
+ text_store_acp_sink_mask_ = 0;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::OnStartComposition(
+ ITfCompositionView* composition_view,
+ BOOL* ok) {
+ if (ok)
+ *ok = TRUE;
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::OnUpdateComposition(
+ ITfCompositionView* composition_view,
+ ITfRange* range) {
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::OnEndComposition(
+ ITfCompositionView* composition_view) {
+ return S_OK;
+}
+
+STDMETHODIMP TSFTextStore::OnEndEdit(ITfContext* context,
+ TfEditCookie read_only_edit_cookie,
+ ITfEditRecord* edit_record) {
+ if (!context || !edit_record)
+ return E_INVALIDARG;
+
+ size_t committed_size;
+ ImeTextSpans spans;
+ if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size,
+ &spans)) {
+ return S_OK;
+ }
+ text_spans_ = spans;
+ committed_size_ = committed_size;
+ edit_flag_ = true;
+ return S_OK;
+}
+
+bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
+ TF_DISPLAYATTRIBUTE* attribute) {
+ GUID guid;
+ if (FAILED(category_manager_->GetGUID(guid_atom, &guid)))
+ return false;
+
+ Microsoft::WRL::ComPtr<ITfDisplayAttributeInfo> display_attribute_info;
+ if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo(
+ guid, display_attribute_info.GetAddressOf(), nullptr))) {
+ return false;
+ }
+ return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
+}
+
+bool TSFTextStore::GetCompositionStatus(
+ ITfContext* context,
+ const TfEditCookie read_only_edit_cookie,
+ size_t* committed_size,
+ ImeTextSpans* spans) {
+ DCHECK(context);
+ DCHECK(committed_size);
+ DCHECK(spans);
+ const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
+ Microsoft::WRL::ComPtr<ITfReadOnlyProperty> track_property;
+ if (FAILED(context->TrackProperties(rgGuids, 2, nullptr, 0,
+ track_property.GetAddressOf()))) {
+ return false;
+ }
+
+ *committed_size = 0;
+ spans->clear();
+ Microsoft::WRL::ComPtr<ITfRange> start_to_end_range;
+ Microsoft::WRL::ComPtr<ITfRange> end_range;
+ if (FAILED(context->GetStart(read_only_edit_cookie,
+ start_to_end_range.GetAddressOf()))) {
+ return false;
+ }
+ if (FAILED(context->GetEnd(read_only_edit_cookie, end_range.GetAddressOf())))
+ return false;
+ if (FAILED(start_to_end_range->ShiftEndToRange(
+ read_only_edit_cookie, end_range.Get(), TF_ANCHOR_END))) {
+ return false;
+ }
+
+ Microsoft::WRL::ComPtr<IEnumTfRanges> ranges;
+ if (FAILED(track_property->EnumRanges(read_only_edit_cookie,
+ ranges.GetAddressOf(),
+ start_to_end_range.Get()))) {
+ return false;
+ }
+
+ while (true) {
+ Microsoft::WRL::ComPtr<ITfRange> range;
+ if (ranges->Next(1, range.GetAddressOf(), nullptr) != S_OK)
+ break;
+ base::win::ScopedVariant value;
+ Microsoft::WRL::ComPtr<IEnumTfPropertyValue> enum_prop_value;
+ if (FAILED(track_property->GetValue(read_only_edit_cookie, range.Get(),
+ value.Receive()))) {
+ return false;
+ }
+ if (FAILED(value.AsInput()->punkVal->QueryInterface(
+ IID_PPV_ARGS(&enum_prop_value))))
+ return false;
+
+ TF_PROPERTYVAL property_value;
+ bool is_composition = false;
+ bool has_display_attribute = false;
+ TF_DISPLAYATTRIBUTE display_attribute = {};
+ while (enum_prop_value->Next(1, &property_value, nullptr) == S_OK) {
+ if (IsEqualGUID(property_value.guidId, GUID_PROP_COMPOSING)) {
+ is_composition = (property_value.varValue.lVal == TRUE);
+ } else if (IsEqualGUID(property_value.guidId, GUID_PROP_ATTRIBUTE)) {
+ TfGuidAtom guid_atom =
+ static_cast<TfGuidAtom>(property_value.varValue.lVal);
+ if (GetDisplayAttribute(guid_atom, &display_attribute))
+ has_display_attribute = true;
+ }
+ VariantClear(&property_value.varValue);
+ }
+
+ Microsoft::WRL::ComPtr<ITfRangeACP> range_acp;
+ range.CopyTo(range_acp.GetAddressOf());
+ LONG start_pos, length;
+ range_acp->GetExtent(&start_pos, &length);
+ if (!is_composition) {
+ if (*committed_size < static_cast<size_t>(start_pos + length))
+ *committed_size = start_pos + length;
+ } else {
+ ImeTextSpan span;
+ span.start_offset = start_pos;
+ span.end_offset = start_pos + length;
+ span.underline_color = SK_ColorBLACK;
+ span.background_color = SK_ColorTRANSPARENT;
+ if (has_display_attribute) {
+ span.thickness = display_attribute.fBoldLine
+ ? ImeTextSpan::Thickness::kThick
+ : ImeTextSpan::Thickness::kThin;
+ }
+ spans->push_back(span);
+ }
+ }
+ return true;
+}
+
+void TSFTextStore::SetFocusedTextInputClient(
+ HWND focused_window,
+ TextInputClient* text_input_client) {
+ window_handle_ = focused_window;
+ text_input_client_ = text_input_client;
+}
+
+void TSFTextStore::RemoveFocusedTextInputClient(
+ TextInputClient* text_input_client) {
+ if (text_input_client_ == text_input_client) {
+ window_handle_ = nullptr;
+ text_input_client_ = nullptr;
+ }
+}
+
+bool TSFTextStore::CancelComposition() {
+ // If there is an on-going document lock, we must not edit the text.
+ if (edit_flag_)
+ return false;
+
+ if (string_buffer_.empty())
+ return true;
+
+ // Unlike ImmNotifyIME(NI_COMPOSITIONSTR, CPS_CANCEL, 0) in IMM32, TSF does
+ // not have a dedicated method to cancel composition. However, CUAS actually
+ // has a protocol conversion from CPS_CANCEL into TSF operations. According
+ // to the observations on Windows 7, TIPs are expected to cancel composition
+ // when an on-going composition text is replaced with an empty string. So
+ // we use the same operation to cancel composition here to minimize the risk
+ // of potential compatibility issues.
+
+ const size_t previous_buffer_size = string_buffer_.size();
+ string_buffer_.clear();
+ committed_size_ = 0;
+ selection_.set_start(0);
+ selection_.set_end(0);
+ if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
+ text_store_acp_sink_->OnSelectionChange();
+ if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+ if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
+ TS_TEXTCHANGE textChange = {};
+ textChange.acpStart = 0;
+ textChange.acpOldEnd = previous_buffer_size;
+ textChange.acpNewEnd = 0;
+ text_store_acp_sink_->OnTextChange(0, &textChange);
+ }
+ return true;
+}
+
+bool TSFTextStore::ConfirmComposition() {
+ // If there is an on-going document lock, we must not edit the text.
+ if (edit_flag_)
+ return false;
+
+ if (string_buffer_.empty())
+ return true;
+
+ // See the comment in TSFTextStore::CancelComposition.
+ // This logic is based on the observation about how to emulate
+ // ImmNotifyIME(NI_COMPOSITIONSTR, CPS_COMPLETE, 0) by CUAS.
+
+ const base::string16& composition_text =
+ string_buffer_.substr(committed_size_);
+ if (!composition_text.empty())
+ text_input_client_->InsertText(composition_text);
+
+ const size_t previous_buffer_size = string_buffer_.size();
+ string_buffer_.clear();
+ committed_size_ = 0;
+ selection_.set_start(0);
+ selection_.set_end(0);
+ if (text_store_acp_sink_mask_ & TS_AS_SEL_CHANGE)
+ text_store_acp_sink_->OnSelectionChange();
+ if (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+ if (text_store_acp_sink_mask_ & TS_AS_TEXT_CHANGE) {
+ TS_TEXTCHANGE textChange = {};
+ textChange.acpStart = 0;
+ textChange.acpOldEnd = previous_buffer_size;
+ textChange.acpNewEnd = 0;
+ text_store_acp_sink_->OnTextChange(0, &textChange);
+ }
+ return true;
+}
+
+void TSFTextStore::SendOnLayoutChange() {
+ if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE))
+ text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+}
+
+bool TSFTextStore::HasReadLock() const {
+ return (current_lock_type_ & TS_LF_READ) == TS_LF_READ;
+}
+
+bool TSFTextStore::HasReadWriteLock() const {
+ return (current_lock_type_ & TS_LF_READWRITE) == TS_LF_READWRITE;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h
new file mode 100644
index 00000000000..687ca8f6d62
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_text_store.h
@@ -0,0 +1,311 @@
+// 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_WIN_TSF_TEXT_STORE_H_
+#define UI_BASE_IME_WIN_TSF_TEXT_STORE_H_
+
+#include <msctf.h>
+#include <wrl/client.h>
+#include <deque>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "ui/base/ime/ime_text_span.h"
+#include "ui/base/ime/ui_base_ime_export.h"
+#include "ui/gfx/range/range.h"
+
+namespace ui {
+class TextInputClient;
+
+// TSFTextStore is used to interact with the input method via TSF manager.
+// TSFTextStore have a string buffer which is manipulated by TSF manager through
+// ITextStoreACP interface methods such as SetText().
+// When the input method updates the composition, TSFTextStore calls
+// TextInputClient::SetCompositionText(). And when the input method finishes the
+// composition, TSFTextStore calls TextInputClient::InsertText() and clears the
+// buffer.
+//
+// How TSFTextStore works:
+// - The user enters "a".
+// - The input method set composition as "a".
+// - TSF manager calls TSFTextStore::RequestLock().
+// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted().
+// - In OnLockGranted(), TSF manager calls
+// - TSFTextStore::OnStartComposition()
+// - TSFTextStore::SetText()
+// The string buffer is set as "a".
+// - TSFTextStore::OnUpdateComposition()
+// - TSFTextStore::OnEndEdit()
+// TSFTextStore can get the composition information such as underlines.
+// - TSFTextStore calls TextInputClient::SetCompositionText().
+// "a" is shown with an underline as composition string.
+// - The user enters <space>.
+// - The input method set composition as "A".
+// - TSF manager calls TSFTextStore::RequestLock().
+// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted().
+// - In OnLockGranted(), TSF manager calls
+// - TSFTextStore::SetText()
+// The string buffer is set as "A".
+// - TSFTextStore::OnUpdateComposition()
+// - TSFTextStore::OnEndEdit()
+// - TSFTextStore calls TextInputClient::SetCompositionText().
+// "A" is shown with an underline as composition string.
+// - The user enters <enter>.
+// - The input method commits "A".
+// - TSF manager calls TSFTextStore::RequestLock().
+// - TSFTextStore callbacks ITextStoreACPSink::OnLockGranted().
+// - In OnLockGranted(), TSF manager calls
+// - TSFTextStore::OnEndComposition()
+// - TSFTextStore::OnEndEdit()
+// TSFTextStore knows "A" is committed.
+// - TSFTextStore calls TextInputClient::InsertText().
+// "A" is shown as committed string.
+// - TSFTextStore clears the string buffer.
+// - TSFTextStore calls OnSelectionChange(), OnLayoutChange() and
+// OnTextChange() of ITextStoreACPSink to let TSF manager know that the
+// string buffer has been changed.
+//
+// About the locking scheme:
+// When TSF manager manipulates the string buffer it calls RequestLock() to get
+// the lock of the document. If TSFTextStore can grant the lock request, it
+// callbacks ITextStoreACPSink::OnLockGranted().
+// RequestLock() is called from only one thread, but called recursively in
+// OnLockGranted() or OnSelectionChange() or OnLayoutChange() or OnTextChange().
+// If the document is locked and the lock request is asynchronous, TSFTextStore
+// queues the request. The queued requests will be handled after the current
+// lock is removed.
+// More information about document locks can be found here:
+// http://msdn.microsoft.com/en-us/library/ms538064
+//
+// More information about TSF can be found here:
+// http://msdn.microsoft.com/en-us/library/ms629032
+class UI_BASE_IME_EXPORT TSFTextStore : public ITextStoreACP,
+ public ITfContextOwnerCompositionSink,
+ public ITfTextEditSink {
+ public:
+ TSFTextStore();
+ virtual ~TSFTextStore();
+
+ // ITextStoreACP:
+ STDMETHOD_(ULONG, AddRef)() override;
+ STDMETHOD_(ULONG, Release)() override;
+ STDMETHOD(QueryInterface)(REFIID iid, void** ppv) override;
+ STDMETHOD(AdviseSink)(REFIID iid, IUnknown* unknown, DWORD mask) override;
+ STDMETHOD(FindNextAttrTransition)
+ (LONG acp_start,
+ LONG acp_halt,
+ ULONG num_filter_attributes,
+ const TS_ATTRID* filter_attributes,
+ DWORD flags,
+ LONG* acp_next,
+ BOOL* found,
+ LONG* found_offset) override;
+ STDMETHOD(GetACPFromPoint)
+ (TsViewCookie view_cookie,
+ const POINT* point,
+ DWORD flags,
+ LONG* acp) override;
+ STDMETHOD(GetActiveView)(TsViewCookie* view_cookie) override;
+ STDMETHOD(GetEmbedded)
+ (LONG acp_pos, REFGUID service, REFIID iid, IUnknown** unknown) override;
+ STDMETHOD(GetEndACP)(LONG* acp) override;
+ STDMETHOD(GetFormattedText)
+ (LONG acp_start, LONG acp_end, IDataObject** data_object) override;
+ STDMETHOD(GetScreenExt)(TsViewCookie view_cookie, RECT* rect) override;
+ STDMETHOD(GetSelection)
+ (ULONG selection_index,
+ ULONG selection_buffer_size,
+ TS_SELECTION_ACP* selection_buffer,
+ ULONG* fetched_count) override;
+ STDMETHOD(GetStatus)(TS_STATUS* pdcs) override;
+ STDMETHOD(GetText)
+ (LONG acp_start,
+ LONG acp_end,
+ wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ ULONG* text_buffer_copied,
+ TS_RUNINFO* run_info_buffer,
+ ULONG run_info_buffer_size,
+ ULONG* run_info_buffer_copied,
+ LONG* next_acp) override;
+ STDMETHOD(GetTextExt)
+ (TsViewCookie view_cookie,
+ LONG acp_start,
+ LONG acp_end,
+ RECT* rect,
+ BOOL* clipped) override;
+ STDMETHOD(GetWnd)(TsViewCookie view_cookie, HWND* window_handle) override;
+ STDMETHOD(InsertEmbedded)
+ (DWORD flags,
+ LONG acp_start,
+ LONG acp_end,
+ IDataObject* data_object,
+ TS_TEXTCHANGE* change) override;
+ STDMETHOD(InsertEmbeddedAtSelection)
+ (DWORD flags,
+ IDataObject* data_object,
+ LONG* acp_start,
+ LONG* acp_end,
+ TS_TEXTCHANGE* change) override;
+ STDMETHOD(InsertTextAtSelection)
+ (DWORD flags,
+ const wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ LONG* acp_start,
+ LONG* acp_end,
+ TS_TEXTCHANGE* text_change) override;
+ STDMETHOD(QueryInsert)
+ (LONG acp_test_start,
+ LONG acp_test_end,
+ ULONG text_size,
+ LONG* acp_result_start,
+ LONG* acp_result_end) override;
+ STDMETHOD(QueryInsertEmbedded)
+ (const GUID* service, const FORMATETC* format, BOOL* insertable) override;
+ STDMETHOD(RequestAttrsAtPosition)
+ (LONG acp_pos,
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer,
+ DWORD flags) override;
+ STDMETHOD(RequestAttrsTransitioningAtPosition)
+ (LONG acp_pos,
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer,
+ DWORD flags) override;
+ STDMETHOD(RequestLock)(DWORD lock_flags, HRESULT* result) override;
+ STDMETHOD(RequestSupportedAttrs)
+ (DWORD flags,
+ ULONG attribute_buffer_size,
+ const TS_ATTRID* attribute_buffer) override;
+ STDMETHOD(RetrieveRequestedAttrs)
+ (ULONG attribute_buffer_size,
+ TS_ATTRVAL* attribute_buffer,
+ ULONG* attribute_buffer_copied) override;
+ STDMETHOD(SetSelection)
+ (ULONG selection_buffer_size,
+ const TS_SELECTION_ACP* selection_buffer) override;
+ STDMETHOD(SetText)
+ (DWORD flags,
+ LONG acp_start,
+ LONG acp_end,
+ const wchar_t* text_buffer,
+ ULONG text_buffer_size,
+ TS_TEXTCHANGE* text_change) override;
+ STDMETHOD(UnadviseSink)(IUnknown* unknown) override;
+
+ // ITfContextOwnerCompositionSink:
+ STDMETHOD(OnStartComposition)
+ (ITfCompositionView* composition_view, BOOL* ok) override;
+ STDMETHOD(OnUpdateComposition)
+ (ITfCompositionView* composition_view, ITfRange* range) override;
+ STDMETHOD(OnEndComposition)(ITfCompositionView* composition_view) override;
+
+ // ITfTextEditSink:
+ STDMETHOD(OnEndEdit)
+ (ITfContext* context,
+ TfEditCookie read_only_edit_cookie,
+ ITfEditRecord* edit_record) override;
+
+ // Sets currently focused TextInputClient.
+ void SetFocusedTextInputClient(HWND focused_window,
+ TextInputClient* text_input_client);
+ // Removes currently focused TextInputClient.
+ void RemoveFocusedTextInputClient(TextInputClient* text_input_client);
+
+ // Cancels the ongoing composition if exists.
+ bool CancelComposition();
+
+ // Confirms the ongoing composition if exists.
+ bool ConfirmComposition();
+
+ // Sends OnLayoutChange() via |text_store_acp_sink_|.
+ void SendOnLayoutChange();
+
+ private:
+ friend class TSFTextStoreTest;
+ friend class TSFTextStoreTestCallback;
+
+ // Checks if the document has a read-only lock.
+ bool HasReadLock() const;
+
+ // Checks if the document has a read and write lock.
+ bool HasReadWriteLock() const;
+
+ // Gets the display attribute structure.
+ bool GetDisplayAttribute(TfGuidAtom guid_atom,
+ TF_DISPLAYATTRIBUTE* attribute);
+
+ // Gets the committed string size and underline information of the context.
+ bool GetCompositionStatus(ITfContext* context,
+ const TfEditCookie read_only_edit_cookie,
+ size_t* committed_size,
+ ImeTextSpans* spans);
+
+ // The refrence count of this instance.
+ volatile LONG ref_count_ = 0;
+
+ // A pointer of ITextStoreACPSink, this instance is given in AdviseSink.
+ Microsoft::WRL::ComPtr<ITextStoreACPSink> text_store_acp_sink_;
+
+ // The current mask of |text_store_acp_sink_|.
+ DWORD text_store_acp_sink_mask_ = 0;
+
+ // HWND of the current view window which is set in SetFocusedTextInputClient.
+ HWND window_handle_ = nullptr;
+
+ // Current TextInputClient which is set in SetFocusedTextInputClient.
+ TextInputClient* text_input_client_ = nullptr;
+
+ // TODO(dtapuska): determine if we can expose more the entire document
+ // more than the committed string and composition string to the TIP.
+ // |string_buffer_| contains committed string and composition string.
+ // Example: "aoi" is committed, and "umi" is under composition.
+ // |string_buffer_|: "aoiumi"
+ // |committed_size_|: 3
+ base::string16 string_buffer_;
+ size_t committed_size_ = 0;
+
+ // |selection_start_| and |selection_end_| indicates the selection range.
+ // Example: "iue" is selected
+ // |string_buffer_|: "aiueo"
+ // |selection_.start()|: 1
+ // |selection_.end()|: 4
+ gfx::Range selection_;
+
+ // |start_offset| and |end_offset| of |text_spans_| indicates
+ // the offsets in |string_buffer_|.
+ // Example: "aoi" is committed. There are two underlines in "umi" and "no".
+ // |string_buffer_|: "aoiumino"
+ // |committed_size_|: 3
+ // text_spans_[0].start_offset: 3
+ // text_spans_[0].end_offset: 6
+ // text_spans_[1].start_offset: 6
+ // text_spans_[1].end_offset: 8
+ ImeTextSpans text_spans_;
+
+ // |edit_flag_| indicates that the status is edited during
+ // ITextStoreACPSink::OnLockGranted().
+ bool edit_flag_ = false;
+
+ // The type of current lock.
+ // 0: No lock.
+ // TS_LF_READ: read-only lock.
+ // TS_LF_READWRITE: read/write lock.
+ DWORD current_lock_type_ = 0;
+
+ // Queue of the lock request used in RequestLock().
+ std::deque<DWORD> lock_queue_;
+
+ // Category manager and Display attribute manager are used to obtain the
+ // attributes of the composition string.
+ Microsoft::WRL::ComPtr<ITfCategoryMgr> category_manager_;
+ Microsoft::WRL::ComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(TSFTextStore);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_WIN_TSF_TEXT_STORE_H_
diff --git a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
new file mode 100644
index 00000000000..76c3eb149d9
--- /dev/null
+++ b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -0,0 +1,1302 @@
+// 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/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>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/scoped_variant.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event.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_METHOD0(ConfirmCompositionText, void());
+ 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_METHOD1(GetTextRange, bool(gfx::Range*));
+ MOCK_CONST_METHOD1(GetCompositionTextRange, bool(gfx::Range*));
+ MOCK_CONST_METHOD1(GetSelectionRange, bool(gfx::Range*));
+ MOCK_METHOD1(SetSelectionRange, bool(const gfx::Range&));
+ MOCK_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(GetClientSourceInfo, const std::string&());
+};
+
+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_;
+};
+
+const HWND kWindowHandle = reinterpret_cast<HWND>(1);
+
+} // namespace
+
+class TSFTextStoreTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ text_store_ = new TSFTextStore();
+ 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_);
+ }
+
+ 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::string16* string_buffer() { return &text_store_->string_buffer_; }
+ size_t* committed_size() { return &text_store_->committed_size_; }
+
+ base::win::ScopedCOMInitializer com_initializer_;
+ MockTextInputClient text_input_client_;
+ scoped_refptr<TSFTextStore> text_store_;
+ scoped_refptr<MockStoreACPSink> sink_;
+};
+
+class TSFTextStoreTestCallback {
+ public:
+ explicit TSFTextStoreTestCallback(TSFTextStore* text_store)
+ : text_store_(text_store) {
+ CHECK(text_store_);
+ }
+ virtual ~TSFTextStoreTestCallback() {}
+
+ protected:
+ // Accessors to the internal state of TSFTextStore.
+ bool* edit_flag() { return &text_store_->edit_flag_; }
+ base::string16* string_buffer() { return &text_store_->string_buffer_; }
+ size_t* committed_size() { return &text_store_->committed_size_; }
+ gfx::Range* selection() { return &text_store_->selection_; }
+ ImeTextSpans* text_spans() { return &text_store_->text_spans_; }
+
+ void SetInternalState(const base::string16& new_string_buffer,
+ LONG new_committed_size,
+ LONG new_selection_start,
+ LONG new_selection_end) {
+ ASSERT_LE(0, new_committed_size);
+ ASSERT_LE(new_committed_size, new_selection_start);
+ ASSERT_LE(new_selection_start, new_selection_end);
+ ASSERT_LE(new_selection_end, static_cast<LONG>(new_string_buffer.size()));
+ *string_buffer() = new_string_buffer;
+ *committed_size() = new_committed_size;
+ selection()->set_start(new_selection_start);
+ selection()->set_end(new_selection_end);
+ }
+
+ bool HasReadLock() const { return text_store_->HasReadLock(); }
+ bool HasReadWriteLock() const { return text_store_->HasReadWriteLock(); }
+
+ void GetSelectionTest(LONG expected_acp_start, LONG expected_acp_end) {
+ TS_SELECTION_ACP selection = {};
+ ULONG fetched = 0;
+ EXPECT_EQ(S_OK, text_store_->GetSelection(0, 1, &selection, &fetched));
+ EXPECT_EQ(1u, fetched);
+ EXPECT_EQ(expected_acp_start, selection.acpStart);
+ EXPECT_EQ(expected_acp_end, selection.acpEnd);
+ }
+
+ void SetSelectionTest(LONG acp_start, LONG acp_end, HRESULT expected_result) {
+ TS_SELECTION_ACP selection = {};
+ selection.acpStart = acp_start;
+ selection.acpEnd = acp_end;
+ selection.style.ase = TS_AE_NONE;
+ selection.style.fInterimChar = 0;
+ EXPECT_EQ(expected_result, text_store_->SetSelection(1, &selection));
+ if (expected_result == S_OK) {
+ GetSelectionTest(acp_start, acp_end);
+ }
+ }
+
+ void SetTextTest(LONG acp_start,
+ LONG acp_end,
+ const base::string16& text,
+ HRESULT error_code) {
+ TS_TEXTCHANGE change = {};
+ ASSERT_EQ(error_code,
+ text_store_->SetText(0, acp_start, acp_end, text.c_str(),
+ text.size(), &change));
+ if (error_code == S_OK) {
+ EXPECT_EQ(acp_start, change.acpStart);
+ EXPECT_EQ(acp_end, change.acpOldEnd);
+ EXPECT_EQ(acp_start + text.size(), (size_t)change.acpNewEnd);
+ }
+ }
+
+ void GetTextTest(LONG acp_start,
+ LONG acp_end,
+ const base::string16& expected_string,
+ LONG expected_next_acp) {
+ wchar_t buffer[1024] = {};
+ ULONG text_buffer_copied = 0;
+ TS_RUNINFO run_info = {};
+ ULONG run_info_buffer_copied = 0;
+ LONG next_acp = 0;
+ ASSERT_EQ(S_OK, text_store_->GetText(acp_start, acp_end, buffer, 1024,
+ &text_buffer_copied, &run_info, 1,
+ &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));
+ EXPECT_EQ(1u, run_info_buffer_copied);
+ EXPECT_EQ(expected_string.size(), run_info.uCount);
+ EXPECT_EQ(TS_RT_PLAIN, run_info.type);
+ EXPECT_EQ(expected_next_acp, next_acp);
+ }
+
+ void GetTextErrorTest(LONG acp_start, LONG acp_end, HRESULT error_code) {
+ wchar_t buffer[1024] = {};
+ ULONG text_buffer_copied = 0;
+ TS_RUNINFO run_info = {};
+ ULONG run_info_buffer_copied = 0;
+ LONG next_acp = 0;
+ EXPECT_EQ(error_code,
+ text_store_->GetText(acp_start, acp_end, buffer, 1024,
+ &text_buffer_copied, &run_info, 1,
+ &run_info_buffer_copied, &next_acp));
+ }
+
+ void InsertTextAtSelectionTest(const wchar_t* buffer,
+ ULONG buffer_size,
+ LONG expected_start,
+ LONG expected_end,
+ LONG expected_change_start,
+ LONG expected_change_old_end,
+ LONG expected_change_new_end) {
+ LONG start = 0;
+ LONG end = 0;
+ TS_TEXTCHANGE change = {};
+ EXPECT_EQ(S_OK, text_store_->InsertTextAtSelection(0, buffer, buffer_size,
+ &start, &end, &change));
+ EXPECT_EQ(expected_start, start);
+ EXPECT_EQ(expected_end, end);
+ EXPECT_EQ(expected_change_start, change.acpStart);
+ EXPECT_EQ(expected_change_old_end, change.acpOldEnd);
+ EXPECT_EQ(expected_change_new_end, change.acpNewEnd);
+ }
+
+ void InsertTextAtSelectionQueryOnlyTest(const wchar_t* buffer,
+ ULONG buffer_size,
+ LONG expected_start,
+ LONG expected_end) {
+ LONG start = 0;
+ LONG end = 0;
+ EXPECT_EQ(S_OK, text_store_->InsertTextAtSelection(TS_IAS_QUERYONLY, buffer,
+ buffer_size, &start,
+ &end, nullptr));
+ EXPECT_EQ(expected_start, start);
+ EXPECT_EQ(expected_end, end);
+ }
+
+ void GetTextExtTest(TsViewCookie view_cookie,
+ LONG acp_start,
+ LONG acp_end,
+ LONG expected_left,
+ LONG expected_top,
+ LONG expected_right,
+ LONG expected_bottom) {
+ RECT rect = {};
+ BOOL clipped = FALSE;
+ EXPECT_EQ(S_OK, text_store_->GetTextExt(view_cookie, acp_start, acp_end,
+ &rect, &clipped));
+ EXPECT_EQ(expected_left, rect.left);
+ EXPECT_EQ(expected_top, rect.top);
+ EXPECT_EQ(expected_right, rect.right);
+ EXPECT_EQ(expected_bottom, rect.bottom);
+ EXPECT_EQ(FALSE, clipped);
+ }
+
+ void GetTextExtNoLayoutTest(TsViewCookie view_cookie,
+ LONG acp_start,
+ LONG acp_end) {
+ RECT rect = {};
+ BOOL clipped = FALSE;
+ EXPECT_EQ(TS_E_NOLAYOUT, text_store_->GetTextExt(view_cookie, acp_start,
+ acp_end, &rect, &clipped));
+ }
+
+ scoped_refptr<TSFTextStore> text_store_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TSFTextStoreTestCallback);
+};
+
+namespace {
+
+const HRESULT kInvalidResult = 0x12345678;
+
+TEST_F(TSFTextStoreTest, GetStatusTest) {
+ TS_STATUS status = {};
+ EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
+ EXPECT_EQ(0u, status.dwDynamicFlags);
+ EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
+ status.dwStaticFlags);
+}
+
+TEST_F(TSFTextStoreTest, QueryInsertTest) {
+ LONG result_start = 0;
+ LONG result_end = 0;
+ *string_buffer() = L"";
+ *committed_size() = 0;
+ EXPECT_EQ(E_INVALIDARG,
+ text_store_->QueryInsert(0, 0, 0, nullptr, &result_end));
+ EXPECT_EQ(E_INVALIDARG,
+ text_store_->QueryInsert(0, 0, 0, &result_start, nullptr));
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(0, 0, 0, &result_start, &result_end));
+ EXPECT_EQ(0, result_start);
+ EXPECT_EQ(0, result_end);
+ *string_buffer() = L"1234";
+ *committed_size() = 1;
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(0, 1, 0, &result_start, &result_end));
+ EXPECT_EQ(1, result_start);
+ EXPECT_EQ(1, result_end);
+ EXPECT_EQ(E_INVALIDARG,
+ text_store_->QueryInsert(1, 0, 0, &result_start, &result_end));
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(2, 2, 0, &result_start, &result_end));
+ EXPECT_EQ(2, result_start);
+ EXPECT_EQ(2, result_end);
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(2, 3, 0, &result_start, &result_end));
+ EXPECT_EQ(2, result_start);
+ EXPECT_EQ(3, result_end);
+ EXPECT_EQ(E_INVALIDARG,
+ text_store_->QueryInsert(3, 2, 0, &result_start, &result_end));
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(3, 4, 0, &result_start, &result_end));
+ EXPECT_EQ(3, result_start);
+ EXPECT_EQ(4, result_end);
+ EXPECT_EQ(S_OK,
+ text_store_->QueryInsert(3, 5, 0, &result_start, &result_end));
+ EXPECT_EQ(3, result_start);
+ EXPECT_EQ(4, result_end);
+}
+
+class SyncRequestLockTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit SyncRequestLockTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ return S_OK;
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ return S_OK;
+ }
+
+ HRESULT LockGranted3(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result));
+ EXPECT_EQ(TS_E_SYNCHRONOUS, result);
+ return S_OK;
+ }
+
+ HRESULT LockGranted4(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK,
+ text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result));
+ EXPECT_EQ(TS_E_SYNCHRONOUS, result);
+ return S_OK;
+ }
+
+ HRESULT LockGranted5(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result));
+ EXPECT_EQ(TS_E_SYNCHRONOUS, result);
+ return S_OK;
+ }
+
+ HRESULT LockGranted6(DWORD flags) {
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK,
+ text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result));
+ EXPECT_EQ(TS_E_SYNCHRONOUS, result);
+ return S_OK;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SyncRequestLockTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, SynchronousRequestLockTest) {
+ SyncRequestLockTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted1))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted2))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted3))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted4))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted5))
+ .WillOnce(Invoke(&callback, &SyncRequestLockTestCallback::LockGranted6));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK,
+ text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK,
+ text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK,
+ text_store_->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+class AsyncRequestLockTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit AsyncRequestLockTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store), state_(0) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ EXPECT_EQ(0, state_);
+ state_ = 1;
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(TS_S_ASYNC, result);
+ EXPECT_EQ(1, state_);
+ state_ = 2;
+ return S_OK;
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ EXPECT_EQ(2, state_);
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(TS_S_ASYNC, result);
+ EXPECT_EQ(2, state_);
+ state_ = 3;
+ return S_OK;
+ }
+
+ HRESULT LockGranted3(DWORD flags) {
+ EXPECT_EQ(3, state_);
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(TS_S_ASYNC, result);
+ EXPECT_EQ(3, state_);
+ state_ = 4;
+ return S_OK;
+ }
+
+ HRESULT LockGranted4(DWORD flags) {
+ EXPECT_EQ(4, state_);
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(TS_S_ASYNC, result);
+ EXPECT_EQ(4, state_);
+ state_ = 5;
+ return S_OK;
+ }
+
+ HRESULT LockGranted5(DWORD flags) {
+ EXPECT_EQ(5, state_);
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_FALSE(HasReadWriteLock());
+ state_ = 6;
+ return S_OK;
+ }
+
+ private:
+ int state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncRequestLockTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, AsynchronousRequestLockTest) {
+ AsyncRequestLockTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted1))
+ .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted2))
+ .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted3))
+ .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted4))
+ .WillOnce(Invoke(&callback, &AsyncRequestLockTestCallback::LockGranted5));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+class RequestLockTextChangeTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit RequestLockTextChangeTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store), state_(0) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ EXPECT_EQ(0, state_);
+ state_ = 1;
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+
+ *edit_flag() = true;
+ SetInternalState(L"012345", 6, 6, 6);
+ text_spans()->clear();
+
+ state_ = 2;
+ return S_OK;
+ }
+
+ void InsertText(const base::string16& text) {
+ EXPECT_EQ(2, state_);
+ EXPECT_EQ(L"012345", text);
+ state_ = 3;
+ }
+
+ void SetCompositionText(const ui::CompositionText& composition) {
+ EXPECT_EQ(3, state_);
+ EXPECT_EQ(L"", composition.text);
+ EXPECT_EQ(0u, composition.selection.start());
+ EXPECT_EQ(0u, composition.selection.end());
+ EXPECT_EQ(0u, composition.ime_text_spans.size());
+ state_ = 4;
+ }
+
+ HRESULT OnTextChange(DWORD flags, const TS_TEXTCHANGE* change) {
+ EXPECT_EQ(4, state_);
+ HRESULT result = kInvalidResult;
+ state_ = 5;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+ EXPECT_EQ(6, state_);
+ state_ = 7;
+ return S_OK;
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ EXPECT_EQ(5, state_);
+ EXPECT_TRUE(HasReadLock());
+ EXPECT_TRUE(HasReadWriteLock());
+ state_ = 6;
+ return S_OK;
+ }
+
+ private:
+ int state_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestLockTextChangeTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, RequestLockOnTextChangeTest) {
+ RequestLockTextChangeTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(
+ Invoke(&callback, &RequestLockTextChangeTestCallback::LockGranted1))
+ .WillOnce(
+ Invoke(&callback, &RequestLockTextChangeTestCallback::LockGranted2));
+
+ EXPECT_CALL(*sink_, OnSelectionChange()).WillOnce(Return(S_OK));
+ EXPECT_CALL(*sink_, OnLayoutChange(_, _)).WillOnce(Return(S_OK));
+ EXPECT_CALL(*sink_, OnTextChange(_, _))
+ .WillOnce(
+ Invoke(&callback, &RequestLockTextChangeTestCallback::OnTextChange));
+ EXPECT_CALL(text_input_client_, InsertText(_))
+ .WillOnce(
+ Invoke(&callback, &RequestLockTextChangeTestCallback::InsertText));
+ EXPECT_CALL(text_input_client_, SetCompositionText(_))
+ .WillOnce(Invoke(&callback,
+ &RequestLockTextChangeTestCallback::SetCompositionText));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+class SelectionTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit SelectionTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT ReadLockGranted(DWORD flags) {
+ SetInternalState(L"", 0, 0, 0);
+
+ GetSelectionTest(0, 0);
+ SetSelectionTest(0, 0, TF_E_NOLOCK);
+
+ SetInternalState(L"012345", 0, 0, 3);
+
+ GetSelectionTest(0, 3);
+ SetSelectionTest(0, 0, TF_E_NOLOCK);
+
+ return S_OK;
+ }
+
+ HRESULT ReadWriteLockGranted(DWORD flags) {
+ SetInternalState(L"", 0, 0, 0);
+
+ SetSelectionTest(0, 0, S_OK);
+ GetSelectionTest(0, 0);
+ SetSelectionTest(0, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 1, TF_E_INVALIDPOS);
+
+ SetInternalState(L"0123456", 3, 3, 3);
+
+ SetSelectionTest(0, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(0, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(0, 3, TF_E_INVALIDPOS);
+ SetSelectionTest(0, 6, TF_E_INVALIDPOS);
+ SetSelectionTest(0, 7, TF_E_INVALIDPOS);
+ SetSelectionTest(0, 8, TF_E_INVALIDPOS);
+
+ SetSelectionTest(1, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 3, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 6, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 7, TF_E_INVALIDPOS);
+ SetSelectionTest(1, 8, TF_E_INVALIDPOS);
+
+ SetSelectionTest(3, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(3, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(3, 3, S_OK);
+ SetSelectionTest(3, 6, S_OK);
+ SetSelectionTest(3, 7, S_OK);
+ SetSelectionTest(3, 8, TF_E_INVALIDPOS);
+
+ SetSelectionTest(6, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(6, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(6, 3, TF_E_INVALIDPOS);
+ SetSelectionTest(6, 6, S_OK);
+ SetSelectionTest(6, 7, S_OK);
+ SetSelectionTest(6, 8, TF_E_INVALIDPOS);
+
+ SetSelectionTest(7, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(7, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(7, 3, TF_E_INVALIDPOS);
+ SetSelectionTest(7, 6, TF_E_INVALIDPOS);
+ SetSelectionTest(7, 7, S_OK);
+ SetSelectionTest(7, 8, TF_E_INVALIDPOS);
+
+ SetSelectionTest(8, 0, TF_E_INVALIDPOS);
+ SetSelectionTest(8, 1, TF_E_INVALIDPOS);
+ SetSelectionTest(8, 3, TF_E_INVALIDPOS);
+ SetSelectionTest(8, 6, TF_E_INVALIDPOS);
+ SetSelectionTest(8, 7, TF_E_INVALIDPOS);
+ SetSelectionTest(8, 8, TF_E_INVALIDPOS);
+
+ return S_OK;
+ }
+};
+
+TEST_F(TSFTextStoreTest, SetGetSelectionTest) {
+ SelectionTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &SelectionTestCallback::ReadLockGranted))
+ .WillOnce(
+ Invoke(&callback, &SelectionTestCallback::ReadWriteLockGranted));
+
+ TS_SELECTION_ACP selection_buffer = {};
+ ULONG fetched_count = 0;
+ EXPECT_EQ(TS_E_NOLOCK,
+ text_store_->GetSelection(0, 1, &selection_buffer, &fetched_count));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+}
+
+class SetGetTextTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit SetGetTextTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT ReadLockGranted(DWORD flags) {
+ SetTextTest(0, 0, L"", TF_E_NOLOCK);
+
+ GetTextTest(0, -1, L"", 0);
+ GetTextTest(0, 0, L"", 0);
+ GetTextErrorTest(0, 1, TF_E_INVALIDPOS);
+
+ SetInternalState(L"0123456", 3, 3, 3);
+
+ GetTextErrorTest(-1, -1, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 0, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 1, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 3, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 6, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 7, TF_E_INVALIDPOS);
+ GetTextErrorTest(-1, 8, TF_E_INVALIDPOS);
+
+ GetTextTest(0, -1, L"0123456", 7);
+ GetTextTest(0, 0, L"", 0);
+ GetTextTest(0, 1, L"0", 1);
+ GetTextTest(0, 3, L"012", 3);
+ GetTextTest(0, 6, L"012345", 6);
+ GetTextTest(0, 7, L"0123456", 7);
+ GetTextErrorTest(0, 8, TF_E_INVALIDPOS);
+
+ GetTextTest(1, -1, L"123456", 7);
+ GetTextErrorTest(1, 0, TF_E_INVALIDPOS);
+ GetTextTest(1, 1, L"", 1);
+ GetTextTest(1, 3, L"12", 3);
+ GetTextTest(1, 6, L"12345", 6);
+ GetTextTest(1, 7, L"123456", 7);
+ GetTextErrorTest(1, 8, TF_E_INVALIDPOS);
+
+ GetTextTest(3, -1, L"3456", 7);
+ GetTextErrorTest(3, 0, TF_E_INVALIDPOS);
+ GetTextErrorTest(3, 1, TF_E_INVALIDPOS);
+ GetTextTest(3, 3, L"", 3);
+ GetTextTest(3, 6, L"345", 6);
+ GetTextTest(3, 7, L"3456", 7);
+ GetTextErrorTest(3, 8, TF_E_INVALIDPOS);
+
+ GetTextTest(6, -1, L"6", 7);
+ GetTextErrorTest(6, 0, TF_E_INVALIDPOS);
+ GetTextErrorTest(6, 1, TF_E_INVALIDPOS);
+ GetTextErrorTest(6, 3, TF_E_INVALIDPOS);
+ GetTextTest(6, 6, L"", 6);
+ GetTextTest(6, 7, L"6", 7);
+ GetTextErrorTest(6, 8, TF_E_INVALIDPOS);
+
+ GetTextTest(7, -1, L"", 7);
+ GetTextErrorTest(7, 0, TF_E_INVALIDPOS);
+ GetTextErrorTest(7, 1, TF_E_INVALIDPOS);
+ GetTextErrorTest(7, 3, TF_E_INVALIDPOS);
+ GetTextErrorTest(7, 6, TF_E_INVALIDPOS);
+ GetTextTest(7, 7, L"", 7);
+ GetTextErrorTest(7, 8, TF_E_INVALIDPOS);
+
+ GetTextErrorTest(8, -1, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 0, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 1, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 3, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 6, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 7, TF_E_INVALIDPOS);
+ GetTextErrorTest(8, 8, TF_E_INVALIDPOS);
+
+ return S_OK;
+ }
+
+ HRESULT ReadWriteLockGranted(DWORD flags) {
+ SetInternalState(L"", 0, 0, 0);
+ SetTextTest(0, 0, L"", S_OK);
+
+ SetInternalState(L"", 0, 0, 0);
+ SetTextTest(0, 1, L"", TS_E_INVALIDPOS);
+
+ SetInternalState(L"0123456", 3, 3, 3);
+
+ SetTextTest(0, 0, L"", TS_E_INVALIDPOS);
+ SetTextTest(0, 1, L"", TS_E_INVALIDPOS);
+ SetTextTest(0, 3, L"", TS_E_INVALIDPOS);
+ SetTextTest(0, 6, L"", TS_E_INVALIDPOS);
+ SetTextTest(0, 7, L"", TS_E_INVALIDPOS);
+ SetTextTest(0, 8, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(1, 0, L"", TS_E_INVALIDPOS);
+ SetTextTest(1, 1, L"", TS_E_INVALIDPOS);
+ SetTextTest(1, 3, L"", TS_E_INVALIDPOS);
+ SetTextTest(1, 6, L"", TS_E_INVALIDPOS);
+ SetTextTest(1, 7, L"", TS_E_INVALIDPOS);
+ SetTextTest(1, 8, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(3, 0, L"", TS_E_INVALIDPOS);
+ SetTextTest(3, 1, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(3, 3, L"", S_OK);
+ GetTextTest(0, -1, L"0123456", 7);
+ GetSelectionTest(3, 3);
+ SetInternalState(L"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);
+
+ SetTextTest(3, 7, L"", S_OK);
+ GetTextTest(0, -1, L"012", 3);
+ GetSelectionTest(3, 3);
+ SetInternalState(L"0123456", 3, 3, 3);
+
+ SetTextTest(3, 8, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(6, 0, L"", TS_E_INVALIDPOS);
+ SetTextTest(6, 1, L"", TS_E_INVALIDPOS);
+ SetTextTest(6, 3, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(6, 6, L"", S_OK);
+ GetTextTest(0, -1, L"0123456", 7);
+ GetSelectionTest(6, 6);
+ SetInternalState(L"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);
+
+ SetTextTest(6, 8, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(7, 0, L"", TS_E_INVALIDPOS);
+ SetTextTest(7, 1, L"", TS_E_INVALIDPOS);
+ SetTextTest(7, 3, L"", TS_E_INVALIDPOS);
+ SetTextTest(7, 6, L"", TS_E_INVALIDPOS);
+
+ SetTextTest(7, 7, L"", S_OK);
+ GetTextTest(0, -1, L"0123456", 7);
+ GetSelectionTest(7, 7);
+ SetInternalState(L"0123456", 3, 3, 3);
+
+ SetTextTest(7, 8, L"", TS_E_INVALIDPOS);
+
+ SetInternalState(L"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);
+ SetTextTest(3, 6, L"abc", S_OK);
+ GetTextTest(0, -1, L"012abc6", 7);
+ GetSelectionTest(3, 6);
+
+ SetInternalState(L"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);
+ SetTextTest(6, 6, L"abc", S_OK);
+ GetTextTest(0, -1, L"012345abc6", 10);
+ GetSelectionTest(6, 9);
+
+ SetInternalState(L"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);
+ SetTextTest(7, 7, L"abc", S_OK);
+ GetTextTest(0, -1, L"0123456abc", 10);
+ GetSelectionTest(7, 10);
+
+ return S_OK;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SetGetTextTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, SetGetTextTest) {
+ SetGetTextTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &SetGetTextTestCallback::ReadLockGranted))
+ .WillOnce(
+ Invoke(&callback, &SetGetTextTestCallback::ReadWriteLockGranted));
+
+ wchar_t buffer[1024] = {};
+ ULONG text_buffer_copied = 0;
+ TS_RUNINFO run_info = {};
+ ULONG run_info_buffer_copied = 0;
+ LONG next_acp = 0;
+ EXPECT_EQ(TF_E_NOLOCK, text_store_->GetText(
+ 0, -1, buffer, 1024, &text_buffer_copied,
+ &run_info, 1, &run_info_buffer_copied, &next_acp));
+ TS_TEXTCHANGE change = {};
+ EXPECT_EQ(TF_E_NOLOCK, text_store_->SetText(0, 0, 0, L"abc", 3, &change));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+}
+
+class InsertTextAtSelectionTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit InsertTextAtSelectionTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT ReadLockGranted(DWORD flags) {
+ const wchar_t kBuffer[] = L"0123456789";
+
+ SetInternalState(L"abcedfg", 0, 0, 0);
+ InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0);
+ GetSelectionTest(0, 0);
+ InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0);
+
+ SetInternalState(L"abcedfg", 0, 2, 5);
+ InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 2, 5);
+ GetSelectionTest(2, 5);
+ InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 2, 5);
+
+ LONG start = 0;
+ LONG end = 0;
+ TS_TEXTCHANGE change = {};
+ EXPECT_EQ(TS_E_NOLOCK, text_store_->InsertTextAtSelection(
+ 0, kBuffer, 10, &start, &end, &change));
+ return S_OK;
+ }
+
+ HRESULT ReadWriteLockGranted(DWORD flags) {
+ SetInternalState(L"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);
+ InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10);
+ GetSelectionTest(0, 10);
+ GetTextTest(0, -1, L"0123456789", 10);
+
+ SetInternalState(L"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);
+ InsertTextAtSelectionTest(kBuffer, 0, 0, 0, 0, 3, 0);
+ GetSelectionTest(0, 0);
+ GetTextTest(0, -1, L"edfg", 4);
+
+ SetInternalState(L"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);
+ InsertTextAtSelectionTest(kBuffer, 10, 7, 17, 7, 7, 17);
+ GetSelectionTest(7, 17);
+ GetTextTest(0, -1, L"abcedfg0123456789", 17);
+
+ return S_OK;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InsertTextAtSelectionTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, InsertTextAtSelectionTest) {
+ InsertTextAtSelectionTestCallback callback(text_store_.get());
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback,
+ &InsertTextAtSelectionTestCallback::ReadLockGranted))
+ .WillOnce(Invoke(
+ &callback, &InsertTextAtSelectionTestCallback::ReadWriteLockGranted));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+class ScenarioTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit ScenarioTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ SetSelectionTest(0, 0, S_OK);
+
+ SetTextTest(0, 0, L"abc", S_OK);
+ SetTextTest(1, 2, L"xyz", S_OK);
+
+ GetTextTest(0, -1, L"axyzc", 5);
+
+ text_spans()->clear();
+ ImeTextSpan text_span;
+ text_span.start_offset = 0;
+ text_span.end_offset = 5;
+ 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;
+ *committed_size() = 0;
+ return S_OK;
+ }
+
+ void SetCompositionText1(const ui::CompositionText& composition) {
+ EXPECT_EQ(L"axyzc", composition.text);
+ EXPECT_EQ(1u, composition.selection.start());
+ EXPECT_EQ(4u, composition.selection.end());
+ ASSERT_EQ(1u, composition.ime_text_spans.size());
+ EXPECT_EQ(SK_ColorBLACK, composition.ime_text_spans[0].underline_color);
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ composition.ime_text_spans[0].background_color);
+ EXPECT_EQ(0u, composition.ime_text_spans[0].start_offset);
+ EXPECT_EQ(5u, composition.ime_text_spans[0].end_offset);
+ EXPECT_EQ(ImeTextSpan::Thickness::kThin,
+ composition.ime_text_spans[0].thickness);
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ SetTextTest(3, 4, L"ZCP", S_OK);
+ GetTextTest(0, -1, L"axyZCPc", 7);
+
+ text_spans()->clear();
+ ImeTextSpan text_span;
+ text_span.start_offset = 3;
+ text_span.end_offset = 5;
+ text_span.underline_color = SK_ColorBLACK;
+ text_span.thickness = ImeTextSpan::Thickness::kThick;
+ text_spans()->push_back(text_span);
+ text_span.start_offset = 5;
+ text_span.end_offset = 7;
+ text_span.underline_color = SK_ColorBLACK;
+ text_span.thickness = ImeTextSpan::Thickness::kThin;
+ text_spans()->push_back(text_span);
+
+ *edit_flag() = true;
+ *committed_size() = 3;
+
+ return S_OK;
+ }
+
+ void InsertText2(const base::string16& text) { EXPECT_EQ(L"axy", text); }
+
+ void SetCompositionText2(const ui::CompositionText& composition) {
+ EXPECT_EQ(L"ZCPc", composition.text);
+ EXPECT_EQ(0u, composition.selection.start());
+ EXPECT_EQ(3u, composition.selection.end());
+ ASSERT_EQ(2u, composition.ime_text_spans.size());
+ EXPECT_EQ(SK_ColorBLACK, composition.ime_text_spans[0].underline_color);
+ EXPECT_EQ(0u, composition.ime_text_spans[0].start_offset);
+ EXPECT_EQ(2u, composition.ime_text_spans[0].end_offset);
+ EXPECT_EQ(ImeTextSpan::Thickness::kThick,
+ composition.ime_text_spans[0].thickness);
+ EXPECT_EQ(SK_ColorBLACK, composition.ime_text_spans[1].underline_color);
+ EXPECT_EQ(2u, composition.ime_text_spans[1].start_offset);
+ EXPECT_EQ(4u, composition.ime_text_spans[1].end_offset);
+ EXPECT_EQ(ImeTextSpan::Thickness::kThin,
+ composition.ime_text_spans[1].thickness);
+ }
+
+ HRESULT LockGranted3(DWORD flags) {
+ GetTextTest(0, -1, L"axyZCPc", 7);
+
+ text_spans()->clear();
+ *edit_flag() = true;
+ *committed_size() = 7;
+
+ return S_OK;
+ }
+
+ void InsertText3(const base::string16& text) { EXPECT_EQ(L"ZCPc", text); }
+
+ void SetCompositionText3(const ui::CompositionText& composition) {
+ EXPECT_EQ(L"", composition.text);
+ EXPECT_EQ(0u, composition.selection.start());
+ EXPECT_EQ(0u, composition.selection.end());
+ EXPECT_EQ(0u, composition.ime_text_spans.size());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScenarioTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, ScenarioTest) {
+ ScenarioTestCallback callback(text_store_.get());
+ EXPECT_CALL(text_input_client_, SetCompositionText(_))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText1))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText2))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText3));
+
+ EXPECT_CALL(text_input_client_, InsertText(_))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText2))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText3));
+
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted1))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted2))
+ .WillOnce(Invoke(&callback, &ScenarioTestCallback::LockGranted3));
+
+ // OnSelectionChange will be called once after LockGranted3().
+ EXPECT_CALL(*sink_, OnSelectionChange()).WillOnce(Return(S_OK));
+
+ // OnLayoutChange will be called once after LockGranted3().
+ EXPECT_CALL(*sink_, OnLayoutChange(_, _)).WillOnce(Return(S_OK));
+
+ // OnTextChange will be called once after LockGranted3().
+ EXPECT_CALL(*sink_, OnTextChange(_, _)).WillOnce(Return(S_OK));
+
+ 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);
+}
+
+class GetTextExtTestCallback : public TSFTextStoreTestCallback {
+ public:
+ explicit GetTextExtTestCallback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store),
+ layout_prepared_character_num_(0) {}
+
+ HRESULT LockGranted(DWORD flags) {
+ SetInternalState(L"0123456789012", 0, 0, 0);
+ layout_prepared_character_num_ = 13;
+
+ TsViewCookie view_cookie = 0;
+ EXPECT_EQ(S_OK, text_store_->GetActiveView(&view_cookie));
+ GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20);
+ GetTextExtTest(view_cookie, 0, 1, 11, 12, 20, 20);
+ GetTextExtTest(view_cookie, 0, 2, 11, 12, 30, 20);
+ GetTextExtTest(view_cookie, 9, 9, 100, 12, 100, 20);
+ GetTextExtTest(view_cookie, 9, 10, 101, 12, 110, 20);
+ GetTextExtTest(view_cookie, 10, 10, 110, 12, 110, 20);
+ GetTextExtTest(view_cookie, 11, 11, 20, 112, 20, 120);
+ GetTextExtTest(view_cookie, 11, 12, 21, 112, 30, 120);
+ GetTextExtTest(view_cookie, 9, 12, 101, 12, 30, 120);
+ GetTextExtTest(view_cookie, 9, 13, 101, 12, 40, 120);
+ GetTextExtTest(view_cookie, 0, 13, 11, 12, 40, 120);
+ GetTextExtTest(view_cookie, 13, 13, 40, 112, 40, 120);
+
+ layout_prepared_character_num_ = 12;
+ GetTextExtNoLayoutTest(view_cookie, 13, 13);
+
+ layout_prepared_character_num_ = 0;
+ GetTextExtNoLayoutTest(view_cookie, 0, 0);
+
+ SetInternalState(L"", 0, 0, 0);
+ GetTextExtTest(view_cookie, 0, 0, 1, 2, 4, 6);
+
+ // Last character is not availabe 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);
+ layout_prepared_character_num_ = 2;
+ 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);
+ layout_prepared_character_num_ = 0;
+ GetTextExtTest(view_cookie, 0, 1, 1, 2, 4, 6);
+ return S_OK;
+ }
+
+ bool GetCompositionCharacterBounds(uint32_t index, gfx::Rect* rect) {
+ if (index >= layout_prepared_character_num_)
+ return false;
+ rect->set_x((index % 10) * 10 + 11);
+ rect->set_y((index / 10) * 100 + 12);
+ rect->set_width(9);
+ rect->set_height(8);
+ return true;
+ }
+
+ gfx::Rect GetCaretBounds() { return gfx::Rect(1, 2, 3, 4); }
+
+ private:
+ uint32_t layout_prepared_character_num_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetTextExtTestCallback);
+};
+
+TEST_F(TSFTextStoreTest, GetTextExtTest) {
+ GetTextExtTestCallback callback(text_store_.get());
+ EXPECT_CALL(text_input_client_, GetCaretBounds())
+ .WillRepeatedly(
+ Invoke(&callback, &GetTextExtTestCallback::GetCaretBounds));
+
+ EXPECT_CALL(text_input_client_, GetCompositionCharacterBounds(_, _))
+ .WillRepeatedly(Invoke(
+ &callback, &GetTextExtTestCallback::GetCompositionCharacterBounds));
+
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &GetTextExtTestCallback::LockGranted));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READ, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+TEST_F(TSFTextStoreTest, RequestSupportedAttrs) {
+ EXPECT_CALL(text_input_client_, GetTextInputType())
+ .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT));
+ EXPECT_CALL(text_input_client_, GetTextInputMode())
+ .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT));
+
+ EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 1, nullptr));
+
+ const TS_ATTRID kUnknownAttributes[] = {GUID_NULL};
+ EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(
+ 0, arraysize(kUnknownAttributes), kUnknownAttributes))
+ << "Must fail for unknown attributes";
+
+ const TS_ATTRID kAttributes[] = {GUID_NULL, GUID_PROP_INPUTSCOPE, GUID_NULL};
+ EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(0, arraysize(kAttributes),
+ kAttributes))
+ << "InputScope must be supported";
+
+ {
+ SCOPED_TRACE("Check if RequestSupportedAttrs fails while focus is lost");
+ // Emulate focus lost
+ text_store_->SetFocusedTextInputClient(nullptr, nullptr);
+ EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 0, nullptr));
+ EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(
+ 0, arraysize(kAttributes), kAttributes));
+ }
+}
+
+TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) {
+ EXPECT_CALL(text_input_client_, GetTextInputType())
+ .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT));
+ EXPECT_CALL(text_input_client_, GetTextInputMode())
+ .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT));
+
+ ULONG num_copied = 0xfffffff;
+ EXPECT_HRESULT_FAILED(
+ text_store_->RetrieveRequestedAttrs(1, nullptr, &num_copied));
+
+ {
+ SCOPED_TRACE("Make sure if InputScope is supported");
+ TS_ATTRVAL buffer[2] = {};
+ num_copied = 0xfffffff;
+ ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(arraysize(buffer),
+ buffer, &num_copied));
+ bool input_scope_found = false;
+ for (size_t i = 0; i < num_copied; ++i) {
+ base::win::ScopedVariant variant;
+ // Move ownership from |buffer[i].varValue| to |variant|.
+ std::swap(*variant.Receive(), buffer[i].varValue);
+ if (IsEqualGUID(buffer[i].idAttr, GUID_PROP_INPUTSCOPE)) {
+ EXPECT_EQ(VT_UNKNOWN, variant.type());
+ Microsoft::WRL::ComPtr<ITfInputScope> input_scope;
+ EXPECT_HRESULT_SUCCEEDED(variant.AsInput()->punkVal->QueryInterface(
+ IID_PPV_ARGS(&input_scope)));
+ input_scope_found = true;
+ // we do not break here to clean up all the retrieved VARIANTs.
+ }
+ }
+ EXPECT_TRUE(input_scope_found);
+ }
+ {
+ SCOPED_TRACE("Check if RetrieveRequestedAttrs fails while focus is lost");
+ // Emulate focus lost
+ text_store_->SetFocusedTextInputClient(nullptr, nullptr);
+ num_copied = 0xfffffff;
+ TS_ATTRVAL buffer[2] = {};
+ EXPECT_HRESULT_FAILED(text_store_->RetrieveRequestedAttrs(
+ arraysize(buffer), buffer, &num_copied));
+ }
+}
+
+} // namespace
+} // namespace ui
diff --git a/chromium/ui/base/l10n/l10n_util_unittest.cc b/chromium/ui/base/l10n/l10n_util_unittest.cc
index 2bfd8c8ad24..35dc4754b70 100644
--- a/chromium/ui/base/l10n/l10n_util_unittest.cc
+++ b/chromium/ui/base/l10n/l10n_util_unittest.cc
@@ -12,7 +12,6 @@
#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/ui/base/material_design/material_design_controller.cc b/chromium/ui/base/material_design/material_design_controller.cc
index e19300ed6e1..5abb641690c 100644
--- a/chromium/ui/base/material_design/material_design_controller.cc
+++ b/chromium/ui/base/material_design/material_design_controller.cc
@@ -14,17 +14,14 @@
#include "ui/base/ui_base_switches.h"
#if defined(OS_CHROMEOS)
-#include "ui/base/touch/touch_device.h"
-#include "ui/events/devices/device_data_manager.h"
-
-#if defined(USE_OZONE)
#include <fcntl.h>
#include "base/files/file_enumerator.h"
+#include "base/files/scoped_file.h"
#include "base/threading/thread_restrictions.h"
+#include "ui/base/touch/touch_device.h"
+#include "ui/events/devices/device_data_manager.h"
#include "ui/events/ozone/evdev/event_device_info.h" // nogncheck
-#endif // defined(USE_OZONE)
-
#endif // defined(OS_CHROMEOS)
#if defined(OS_WIN)
@@ -33,6 +30,48 @@
#endif
namespace ui {
+namespace {
+
+#if defined(OS_CHROMEOS)
+
+// Whether to use MATERIAL_TOUCH_OPTIMIZED when a touch device is detected.
+// Enabled by default on ChromeOS.
+const base::Feature kTouchOptimizedUi = {"TouchOptimizedUi",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+MaterialDesignController::Mode GetDefaultTouchDeviceMode() {
+ return base::FeatureList::IsEnabled(kTouchOptimizedUi)
+ ? MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED
+ : MaterialDesignController::MATERIAL_HYBRID;
+}
+
+bool HasTouchscreen() {
+ // If a scan of available devices has already completed, use that.
+ if (DeviceDataManager::HasInstance() &&
+ DeviceDataManager::GetInstance()->AreDeviceListsComplete())
+ return GetTouchScreensAvailability() == TouchScreensAvailability::ENABLED;
+
+ // Otherwise perform our own scan to determine the presence of a touchscreen.
+ // Note this is a one-time call that occurs during device startup or restart.
+ base::FileEnumerator file_enum(
+ base::FilePath(FILE_PATH_LITERAL("/dev/input")), false,
+ base::FileEnumerator::FILES, FILE_PATH_LITERAL("event*[0-9]"));
+ for (base::FilePath path = file_enum.Next(); !path.empty();
+ path = file_enum.Next()) {
+ EventDeviceInfo devinfo;
+ base::ScopedFD fd(
+ open(path.value().c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC));
+ if (fd.is_valid() && devinfo.Initialize(fd.get(), path) &&
+ devinfo.HasTouchscreen())
+ return true;
+ }
+
+ return false;
+}
+
+#endif // OS_CHROMEOS
+
+} // namespace
bool MaterialDesignController::is_mode_initialized_ = false;
@@ -53,6 +92,8 @@ void MaterialDesignController::Initialize() {
SetMode(MATERIAL_HYBRID);
} else if (switch_value == switches::kTopChromeMDMaterialTouchOptimized) {
SetMode(MATERIAL_TOUCH_OPTIMIZED);
+ } else if (switch_value == switches::kTopChromeMDMaterialRefresh) {
+ SetMode(MATERIAL_REFRESH);
} else if (switch_value == switches::kTopChromeMDMaterialAuto) {
#if defined(OS_WIN)
// TODO(girard): add support for switching between modes when
@@ -79,7 +120,8 @@ MaterialDesignController::Mode MaterialDesignController::GetMode() {
// static
bool MaterialDesignController::IsSecondaryUiMaterial() {
- return base::FeatureList::IsEnabled(features::kSecondaryUiMd);
+ return base::FeatureList::IsEnabled(features::kSecondaryUiMd) ||
+ GetMode() == MATERIAL_REFRESH;
}
// static
@@ -88,37 +130,18 @@ bool MaterialDesignController::IsTouchOptimizedUiEnabled() {
}
// static
+bool MaterialDesignController::IsNewerMaterialUi() {
+ return IsTouchOptimizedUiEnabled() || GetMode() == MATERIAL_REFRESH;
+}
+
+// static
MaterialDesignController::Mode MaterialDesignController::DefaultMode() {
#if defined(OS_CHROMEOS)
- // If a scan of available devices has already completed, use material-hybrid
- // if a touchscreen is present.
- if (DeviceDataManager::HasInstance() &&
- DeviceDataManager::GetInstance()->AreDeviceListsComplete()) {
- return GetTouchScreensAvailability() == TouchScreensAvailability::ENABLED
- ? MATERIAL_HYBRID
- : MATERIAL_NORMAL;
- }
-
-#if defined(USE_OZONE)
- // Otherwise perform our own scan to determine the presence of a touchscreen.
- // Note this is a one-time call that occurs during device startup or restart.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- base::FileEnumerator file_enum(
- base::FilePath(FILE_PATH_LITERAL("/dev/input")), false,
- base::FileEnumerator::FILES, FILE_PATH_LITERAL("event*[0-9]"));
- for (base::FilePath path = file_enum.Next(); !path.empty();
- path = file_enum.Next()) {
- EventDeviceInfo devinfo;
- int fd = open(path.value().c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC);
- if (fd >= 0) {
- if (devinfo.Initialize(fd, path) && devinfo.HasTouchscreen()) {
- close(fd);
- return MATERIAL_HYBRID;
- }
- close(fd);
- }
- }
-#endif // defined(USE_OZONE)
+ // This is called (once) early in device startup to initialize core UI, so
+ // the UI thread should be blocked to perform the device query.
+ base::ScopedAllowBlocking allow_io;
+ if (HasTouchscreen())
+ return GetDefaultTouchDeviceMode();
#endif // defined(OS_CHROMEOS)
return MATERIAL_NORMAL;
diff --git a/chromium/ui/base/material_design/material_design_controller.h b/chromium/ui/base/material_design/material_design_controller.h
index 731b304ad51..d9612eabcbb 100644
--- a/chromium/ui/base/material_design/material_design_controller.h
+++ b/chromium/ui/base/material_design/material_design_controller.h
@@ -25,7 +25,9 @@ class UI_BASE_EXPORT MaterialDesignController {
// Material design targeted at mouse/touch hybrid devices.
MATERIAL_HYBRID = 1,
// Material design that is more optimized for touch devices.
- MATERIAL_TOUCH_OPTIMIZED = 2
+ MATERIAL_TOUCH_OPTIMIZED = 2,
+ // Material Refresh design targeted at mouse devices.
+ MATERIAL_REFRESH = 3,
};
// Initializes |mode_|. Must be called before checking |mode_|.
@@ -38,9 +40,12 @@ class UI_BASE_EXPORT MaterialDesignController {
// should be extended to cover secondary UI.
static bool IsSecondaryUiMaterial();
- // Returns true if the touch-optimized UI material design mode is enabled;
+ // Returns true if the touch-optimized UI material design mode is enabled.
static bool IsTouchOptimizedUiEnabled();
+ // Returns true if the Material Refresh or touch-optimized UI is enabled.
+ static bool IsNewerMaterialUi();
+
// Returns the per-platform default material design variant.
static Mode DefaultMode();
diff --git a/chromium/ui/base/models/list_model.h b/chromium/ui/base/models/list_model.h
index d55719c3b83..d8abe8a630e 100644
--- a/chromium/ui/base/models/list_model.h
+++ b/chromium/ui/base/models/list_model.h
@@ -13,7 +13,6 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/observer_list.h"
#include "ui/base/models/list_model_observer.h"
diff --git a/chromium/ui/base/models/list_model_unittest.cc b/chromium/ui/base/models/list_model_unittest.cc
index 38ec54040c0..b5917bf2afc 100644
--- a/chromium/ui/base/models/list_model_unittest.cc
+++ b/chromium/ui/base/models/list_model_unittest.cc
@@ -10,7 +10,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ui {
diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc
index 081f550689f..b7b34292c48 100644
--- a/chromium/ui/base/models/simple_menu_model.cc
+++ b/chromium/ui/base/models/simple_menu_model.cc
@@ -83,6 +83,20 @@ void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) {
AddItem(command_id, l10n_util::GetStringUTF16(string_id));
}
+void SimpleMenuModel::AddItemWithIcon(int command_id,
+ const base::string16& label,
+ const gfx::ImageSkia& icon) {
+ Item item(command_id, TYPE_COMMAND, label);
+ item.icon = gfx::Image(icon);
+ AppendItem(std::move(item));
+}
+
+void SimpleMenuModel::AddItemWithStringIdAndIcon(int command_id,
+ int string_id,
+ const gfx::ImageSkia& icon) {
+ AddItemWithIcon(command_id, l10n_util::GetStringUTF16(string_id), icon);
+}
+
void SimpleMenuModel::AddCheckItem(int command_id,
const base::string16& label) {
AppendItem(Item(command_id, TYPE_CHECK, label));
@@ -386,8 +400,8 @@ void SimpleMenuModel::MenuWillClose() {
// called after this. It's more convenient for the delegate to be called
// afterwards though, so post a task.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&SimpleMenuModel::OnMenuClosed, method_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&SimpleMenuModel::OnMenuClosed,
+ method_factory_.GetWeakPtr()));
}
void SimpleMenuModel::SetMenuModelDelegate(
diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h
index 72bf5e0907e..ecc620a073a 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -75,6 +75,12 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
// Methods for adding items to the model.
void AddItem(int command_id, const base::string16& label);
void AddItemWithStringId(int command_id, int string_id);
+ void AddItemWithIcon(int command_id,
+ const base::string16& label,
+ const gfx::ImageSkia& icon);
+ void AddItemWithStringIdAndIcon(int command_id,
+ int string_id,
+ const gfx::ImageSkia& icon);
void AddCheckItem(int command_id, const base::string16& label);
void AddCheckItemWithStringId(int command_id, int string_id);
void AddRadioItem(int command_id, const base::string16& label, int group_id);
diff --git a/chromium/ui/base/models/tree_node_iterator_unittest.cc b/chromium/ui/base/models/tree_node_iterator_unittest.cc
index a986c5de684..b1c09f506f5 100644
--- a/chromium/ui/base/models/tree_node_iterator_unittest.cc
+++ b/chromium/ui/base/models/tree_node_iterator_unittest.cc
@@ -5,7 +5,6 @@
#include "ui/base/models/tree_node_iterator.h"
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/models/tree_node_model.h"
diff --git a/chromium/ui/base/models/tree_node_model_unittest.cc b/chromium/ui/base/models/tree_node_model_unittest.cc
index 0649f65670b..b39d82bccf3 100644
--- a/chromium/ui/base/models/tree_node_model_unittest.cc
+++ b/chromium/ui/base/models/tree_node_model_unittest.cc
@@ -8,7 +8,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/ui/base/mojo/DEPS b/chromium/ui/base/mojo/DEPS
index e0c12f73402..0e01cbe71d1 100644
--- a/chromium/ui/base/mojo/DEPS
+++ b/chromium/ui/base/mojo/DEPS
@@ -1,4 +1,4 @@
include_rules = [
"+mojo/public/cpp/bindings",
- "+third_party/WebKit/public/mojom/clipboard/clipboard.mojom-shared.h"
+ "+third_party/blink/public/mojom/clipboard/clipboard.mojom-shared.h"
]
diff --git a/chromium/ui/base/mojo/clipboard.typemap b/chromium/ui/base/mojo/clipboard.typemap
index ebd328b5ad3..5f9f30d5182 100644
--- a/chromium/ui/base/mojo/clipboard.typemap
+++ b/chromium/ui/base/mojo/clipboard.typemap
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//third_party/WebKit/public/mojom/clipboard/clipboard.mojom"
+mojom = "//third_party/blink/public/mojom/clipboard/clipboard.mojom"
public_headers = [ "//ui/base/clipboard/clipboard_types.h" ]
traits_headers = [ "//ui/base/mojo/clipboard_struct_traits.h" ]
deps = [
diff --git a/chromium/ui/base/mojo/clipboard_struct_traits.h b/chromium/ui/base/mojo/clipboard_struct_traits.h
index 280a1f2bc97..fb3f50106b1 100644
--- a/chromium/ui/base/mojo/clipboard_struct_traits.h
+++ b/chromium/ui/base/mojo/clipboard_struct_traits.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_MOJO_CLIPBOARD_STRUCT_TRAITS_H_
#define UI_BASE_MOJO_CLIPBOARD_STRUCT_TRAITS_H_
-#include "third_party/WebKit/public/mojom/clipboard/clipboard.mojom-shared.h"
+#include "third_party/blink/public/mojom/clipboard/clipboard.mojom-shared.h"
#include "ui/base/clipboard/clipboard_types.h"
namespace mojo {
diff --git a/chromium/ui/base/nine_image_painter_factory.cc b/chromium/ui/base/nine_image_painter_factory.cc
index 12f59535e3d..57d41f58822 100644
--- a/chromium/ui/base/nine_image_painter_factory.cc
+++ b/chromium/ui/base/nine_image_painter_factory.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/memory/ptr_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/nine_image_painter.h"
diff --git a/chromium/ui/base/resource/data_pack.cc b/chromium/ui/base/resource/data_pack.cc
index 170fa1d05d3..f6cbde5fcc5 100644
--- a/chromium/ui/base/resource/data_pack.cc
+++ b/chromium/ui/base/resource/data_pack.cc
@@ -14,7 +14,6 @@
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index 3bfd3cd883b..bc8da0f069e 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -16,7 +16,6 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#include "base/stl_util.h"
@@ -214,10 +213,8 @@ void ResourceBundle::InitSharedInstanceWithPakPath(const base::FilePath& path) {
// static
void ResourceBundle::CleanupSharedInstance() {
- if (g_shared_instance_) {
- delete g_shared_instance_;
- g_shared_instance_ = NULL;
- }
+ delete g_shared_instance_;
+ g_shared_instance_ = NULL;
}
// static
diff --git a/chromium/ui/base/resource/resource_bundle_android.cc b/chromium/ui/base/resource/resource_bundle_android.cc
index a91fdabe964..2ebf50bab98 100644
--- a/chromium/ui/base/resource/resource_bundle_android.cc
+++ b/chromium/ui/base/resource/resource_bundle_android.cc
@@ -8,7 +8,6 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "jni/ResourceBundle_jni.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chromium/ui/base/resource/resource_bundle_win.cc b/chromium/ui/base/resource/resource_bundle_win.cc
index 54fca6fa0c6..d9f74a5656e 100644
--- a/chromium/ui/base/resource/resource_bundle_win.cc
+++ b/chromium/ui/base/resource/resource_bundle_win.cc
@@ -5,7 +5,6 @@
#include "ui/base/resource/resource_bundle_win.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "skia/ext/image_operations.h"
diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc
index 3e1850d3f45..6de12e2caf4 100644
--- a/chromium/ui/base/ui_base_features.cc
+++ b/chromium/ui/base/ui_base_features.cc
@@ -12,10 +12,23 @@
namespace features {
+// If enabled, the emoji picker context menu item may be shown for editable
+// text areas.
+const base::Feature kEnableEmojiContextMenu{"EnableEmojiContextMenu",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables the floating virtual keyboard behavior.
const base::Feature kEnableFloatingVirtualKeyboard = {
"enable-floating-virtual-keyboard", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the full screen handwriting virtual keyboard behavior.
+const base::Feature kEnableFullscreenHandwritingVirtualKeyboard = {
+ "enable-fullscreen-handwriting-virtual-keyboard",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kEnableStylusVirtualKeyboard = {
+ "enable-stylus-virtual-keyboard", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Applies the material design mode to elements throughout Chrome (not just top
// Chrome).
const base::Feature kSecondaryUiMd = {"SecondaryUiMd",
@@ -45,11 +58,22 @@ const base::Feature kDirectManipulationStylus = {
// Enables using WM_POINTER instead of WM_TOUCH for touch events.
const base::Feature kPointerEventsForTouch = {"PointerEventsForTouch",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables using TSF (over IMM32) for IME.
+const base::Feature kTSFImeSupport = {"TSFImeSupport",
+ base::FEATURE_DISABLED_BY_DEFAULT};
bool IsUsingWMPointerForTouch() {
return base::win::GetVersion() >= base::win::VERSION_WIN8 &&
base::FeatureList::IsEnabled(kPointerEventsForTouch);
}
+
+// Enables DirectManipulation API for processing Precision Touchpad events.
+const base::Feature kPrecisionTouchpad{"PrecisionTouchpad",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables Swipe left/right to navigation back/forward API for processing
+// Precision Touchpad events.
+const base::Feature kPrecisionTouchpadScrollPhase{
+ "PrecisionTouchpadScrollPhase", base::FEATURE_ENABLED_BY_DEFAULT};
#endif // defined(OS_WIN)
// Used to have ash run in its own process. This implicitly turns on the
@@ -69,4 +93,28 @@ bool IsMusEnabled() {
#endif
}
+#if defined(OS_MACOSX)
+// When enabled, the NSWindows for apps will be created in the app's process,
+// and will forward input to the browser process.
+const base::Feature kHostWindowsInAppShimProcess{
+ "HostWindowsInAppShimProcess", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool HostWindowsInAppShimProcess() {
+ return base::FeatureList::IsEnabled(kHostWindowsInAppShimProcess);
+}
+
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+// Causes Views browser builds to use Views browser windows by default rather
+// than Cocoa browser windows.
+const base::Feature kViewsBrowserWindows{"ViewsBrowserWindows",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Returns whether a Views-capable browser build should use the Cocoa browser
+// UI.
+bool IsViewsBrowserCocoa() {
+ return !base::FeatureList::IsEnabled(kViewsBrowserWindows);
+}
+#endif // BUILDFLAG(MAC_VIEWS_BROWSER)
+#endif // defined(OS_MACOSX)
+
} // namespace features
diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h
index acff7278164..d5337023507 100644
--- a/chromium/ui/base/ui_base_features.h
+++ b/chromium/ui/base/ui_base_features.h
@@ -8,11 +8,16 @@
#include "base/feature_list.h"
#include "build/build_config.h"
#include "ui/base/ui_base_export.h"
+#include "ui/base/ui_features.h"
namespace features {
// Keep sorted!
+UI_BASE_EXPORT extern const base::Feature kEnableEmojiContextMenu;
UI_BASE_EXPORT extern const base::Feature kEnableFloatingVirtualKeyboard;
+UI_BASE_EXPORT extern const base::Feature
+ kEnableFullscreenHandwritingVirtualKeyboard;
+UI_BASE_EXPORT extern const base::Feature kEnableStylusVirtualKeyboard;
UI_BASE_EXPORT extern const base::Feature kSecondaryUiMd;
UI_BASE_EXPORT extern const base::Feature kTouchableAppContextMenu;
@@ -21,6 +26,9 @@ UI_BASE_EXPORT bool IsTouchableAppContextMenuEnabled();
#if defined(OS_WIN)
UI_BASE_EXPORT extern const base::Feature kDirectManipulationStylus;
UI_BASE_EXPORT extern const base::Feature kPointerEventsForTouch;
+UI_BASE_EXPORT extern const base::Feature kPrecisionTouchpad;
+UI_BASE_EXPORT extern const base::Feature kPrecisionTouchpadScrollPhase;
+UI_BASE_EXPORT extern const base::Feature kTSFImeSupport;
// Returns true if the system should use WM_POINTER events for touch events.
UI_BASE_EXPORT bool IsUsingWMPointerForTouch();
@@ -38,6 +46,20 @@ UI_BASE_EXPORT extern const base::Feature kMus;
// TODO(sky): rename this to IsWindowServiceEnabled().
UI_BASE_EXPORT bool IsMusEnabled();
+#if defined(OS_MACOSX)
+// Returns true if the NSWindows for apps will be created in the app's process,
+// and will forward input to the browser process.
+UI_BASE_EXPORT bool HostWindowsInAppShimProcess();
+
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+UI_BASE_EXPORT extern const base::Feature kViewsBrowserWindows;
+
+// Returns whether a Views-capable browser build should use the Cocoa browser
+// UI.
+UI_BASE_EXPORT bool IsViewsBrowserCocoa();
+#endif // BUILDFLAG(MAC_VIEWS_BROWSER)
+#endif // defined(OS_MACOSX)
+
} // namespace features
#endif // UI_BASE_UI_BASE_FEATURES_H_
diff --git a/chromium/ui/base/ui_base_switches.cc b/chromium/ui/base/ui_base_switches.cc
index 254140166bc..c8d658d43fa 100644
--- a/chromium/ui/base/ui_base_switches.cc
+++ b/chromium/ui/base/ui_base_switches.cc
@@ -14,6 +14,9 @@ const char kDisableAVFoundationOverlays[] = "disable-avfoundation-overlays";
// based overlay display path.
const char kDisableMacOverlays[] = "disable-mac-overlays";
+// Disable animations for showing and hiding modal dialogs.
+const char kDisableModalAnimations[] = "disable-modal-animations";
+
// Disable use of cross-process CALayers to display content directly from the
// GPU process on Mac.
const char kDisableRemoteCoreAnimation[] = "disable-remote-core-animation";
@@ -78,8 +81,9 @@ const char kTopChromeMDMaterialHybrid[] = "material-hybrid";
// |kTopChromeMD| switch.
const char kTopChromeMDMaterialTouchOptimized[] = "material-touch-optimized";
-// Classic, non-material, mode for the |kTopChromeMD| switch.
-const char kTopChromeMDNonMaterial[] = "non-material";
+// Material design mode that represents a refresh of the Chrome UI for the
+// |kTopChromeMD| switch.
+const char kTopChromeMDMaterialRefresh[] = "material-refresh";
// Disable partial swap which is needed for some OpenGL drivers / emulators.
const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
@@ -96,6 +100,11 @@ const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
// Red: Overdrawn four or more times.
const char kShowOverdrawFeedback[] = "show-overdraw-feedback";
+// Use Skia Deferred Display List, with this option, SkiaRenderer will record
+// frames to Skia DDLs and play them back on the GPU thread. This flag is only
+// be effective with --use-skia-renderer.
+const char kUseSkiaDeferredDisplayList[] = "use-skia-deferred-display-list";
+
// Use SkiaRenderer instead of GLRenderer for direct rendering.
const char kUseSkiaRenderer[] = "use-skia-renderer";
diff --git a/chromium/ui/base/ui_base_switches.h b/chromium/ui/base/ui_base_switches.h
index 2ce580331e3..22a9f4983d7 100644
--- a/chromium/ui/base/ui_base_switches.h
+++ b/chromium/ui/base/ui_base_switches.h
@@ -15,6 +15,7 @@ namespace switches {
#if defined(OS_MACOSX) && !defined(OS_IOS)
UI_BASE_EXPORT extern const char kDisableAVFoundationOverlays[];
UI_BASE_EXPORT extern const char kDisableMacOverlays[];
+UI_BASE_EXPORT extern const char kDisableModalAnimations[];
UI_BASE_EXPORT extern const char kDisableRemoteCoreAnimation[];
UI_BASE_EXPORT extern const char kShowMacOverlayBorders[];
#endif
@@ -38,8 +39,9 @@ UI_BASE_EXPORT extern const char kTopChromeMDMaterial[];
UI_BASE_EXPORT extern const char kTopChromeMDMaterialAuto[];
UI_BASE_EXPORT extern const char kTopChromeMDMaterialHybrid[];
UI_BASE_EXPORT extern const char kTopChromeMDMaterialTouchOptimized[];
-UI_BASE_EXPORT extern const char kTopChromeMDNonMaterial[];
+UI_BASE_EXPORT extern const char kTopChromeMDMaterialRefresh[];
UI_BASE_EXPORT extern const char kUIDisablePartialSwap[];
+UI_BASE_EXPORT extern const char kUseSkiaDeferredDisplayList[];
UI_BASE_EXPORT extern const char kUseSkiaRenderer[];
// Test related.
diff --git a/chromium/ui/base/ui_features.gni b/chromium/ui/base/ui_features.gni
index 806ef9505ad..25f99803ab7 100644
--- a/chromium/ui/base/ui_features.gni
+++ b/chromium/ui/base/ui_features.gni
@@ -9,7 +9,7 @@ declare_args() {
use_xkbcommon = false
# Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
- mac_views_browser = false
+ mac_views_browser = is_mac
# Whether the platform provides a native accessibility toolkit.
has_native_accessibility = use_atk || is_win || is_mac
@@ -20,11 +20,6 @@ declare_args() {
# Set to true to if mus (aka the UI service) is enabled. Use the features kMus
# (or kMash in chrome code) to start in mus/mash.
enable_mus = is_chromeos
-
- # Optimize parts of Chrome's UI written with web technologies (HTML/CSS/JS)
- # for runtime performance purposes. This does more work at compile time for
- # speed benefits at runtime (so we skip in debug builds).
- optimize_webui = !is_debug
}
enable_hidpi = is_mac || is_win || is_linux
diff --git a/chromium/ui/base/user_activity/user_activity_detector.cc b/chromium/ui/base/user_activity/user_activity_detector.cc
index a163830f657..c45121d2c9e 100644
--- a/chromium/ui/base/user_activity/user_activity_detector.cc
+++ b/chromium/ui/base/user_activity/user_activity_detector.cc
@@ -51,15 +51,15 @@ UserActivityDetector::UserActivityDetector() {
CHECK(!g_instance);
g_instance = this;
- ui::PlatformEventSource* platform_event_source =
- ui::PlatformEventSource::GetInstance();
+ PlatformEventSource* platform_event_source =
+ PlatformEventSource::GetInstance();
if (platform_event_source)
platform_event_source->AddPlatformEventObserver(this);
}
UserActivityDetector::~UserActivityDetector() {
- ui::PlatformEventSource* platform_event_source =
- ui::PlatformEventSource::GetInstance();
+ PlatformEventSource* platform_event_source =
+ PlatformEventSource::GetInstance();
if (platform_event_source)
platform_event_source->RemovePlatformEventObserver(this);
g_instance = nullptr;
diff --git a/chromium/ui/base/user_activity/user_activity_detector.h b/chromium/ui/base/user_activity/user_activity_detector.h
index dab5bc407a0..c12fbd4868c 100644
--- a/chromium/ui/base/user_activity/user_activity_detector.h
+++ b/chromium/ui/base/user_activity/user_activity_detector.h
@@ -18,7 +18,7 @@ namespace ui {
class UserActivityObserver;
// Watches for input events and notifies observers that the user is active.
-class UI_BASE_EXPORT UserActivityDetector : public ui::PlatformEventObserver {
+class UI_BASE_EXPORT UserActivityDetector : public PlatformEventObserver {
public:
// Minimum amount of time between notifications to observers.
static const int kNotifyIntervalMs;
@@ -49,7 +49,7 @@ class UI_BASE_EXPORT UserActivityDetector : public ui::PlatformEventObserver {
// PlatformEventSource (e.g. the window server).
void HandleExternalUserActivity();
- // ui::PlatformEventObserver:
+ // PlatformEventObserver:
void WillProcessEvent(const PlatformEvent& platform_event) override {}
void DidProcessEvent(const PlatformEvent& platform_event) override;
diff --git a/chromium/ui/base/user_activity/user_activity_detector_unittest.cc b/chromium/ui/base/user_activity/user_activity_detector_unittest.cc
index b2decd61f41..82b26d238a5 100644
--- a/chromium/ui/base/user_activity/user_activity_detector_unittest.cc
+++ b/chromium/ui/base/user_activity/user_activity_detector_unittest.cc
@@ -41,7 +41,7 @@ class TestUserActivityObserver : public UserActivityObserver {
// A test implementation of PlatformEventSource that we can instantiate to make
// sure that the PlatformEventSource has an instance while in unit tests.
-class TestPlatformEventSource : public ui::PlatformEventSource {
+class TestPlatformEventSource : public PlatformEventSource {
public:
TestPlatformEventSource() {}
~TestPlatformEventSource() override {}
diff --git a/chromium/ui/base/win/direct_manipulation.cc b/chromium/ui/base/win/direct_manipulation.cc
index 78f19277727..52daec79488 100644
--- a/chromium/ui/base/win/direct_manipulation.cc
+++ b/chromium/ui/base/win/direct_manipulation.cc
@@ -5,60 +5,96 @@
#include "ui/base/win/direct_manipulation.h"
#include <objbase.h>
+#include <cmath>
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_version.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/display/win/screen_win.h"
namespace ui {
namespace win {
// static
std::unique_ptr<DirectManipulationHelper>
-DirectManipulationHelper::CreateInstance() {
- // TODO(dtapuska): Do not create a DirectManipulationHelper on any windows
- // versions as it only causes issues. High Precision Touchpad events seem to
- // always be sent to apps with recent Windows 10 versions. This class should
- // eventually be removed. See https://crbug.com/647038.
+DirectManipulationHelper::CreateInstance(HWND window,
+ WindowEventTarget* event_target) {
+ if (!::IsWindow(window))
+ return nullptr;
+
+ if (!base::FeatureList::IsEnabled(features::kPrecisionTouchpad))
+ return nullptr;
+
+ // DM_POINTERHITTEST supported since Win10.
+ if (base::win::GetVersion() < base::win::VERSION_WIN10)
+ return nullptr;
+
+ std::unique_ptr<DirectManipulationHelper> instance =
+ base::WrapUnique(new DirectManipulationHelper());
+ instance->window_ = window;
+
+ if (instance->Initialize(event_target))
+ return instance;
+
return nullptr;
}
-DirectManipulationHelper::DirectManipulationHelper() {}
+// static
+std::unique_ptr<DirectManipulationHelper>
+DirectManipulationHelper::CreateInstanceForTesting(
+ WindowEventTarget* event_target,
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport) {
+ if (!base::FeatureList::IsEnabled(features::kPrecisionTouchpad))
+ return nullptr;
+
+ // DM_POINTERHITTEST supported since Win10.
+ if (base::win::GetVersion() < base::win::VERSION_WIN10)
+ return nullptr;
+
+ std::unique_ptr<DirectManipulationHelper> instance =
+ base::WrapUnique(new DirectManipulationHelper());
+
+ instance->event_handler_ = Microsoft::WRL::Make<DirectManipulationHandler>(
+ instance.get(), event_target);
+
+ instance->viewport_ = viewport;
+
+ return instance;
+}
DirectManipulationHelper::~DirectManipulationHelper() {
- if (view_port_outer_)
- view_port_outer_->Abandon();
+ if (viewport_)
+ viewport_->Abandon();
}
-void DirectManipulationHelper::Initialize(HWND window) {
- DCHECK(::IsWindow(window));
+DirectManipulationHelper::DirectManipulationHelper() {}
+
+// We only use Direct Manipulation as event handler so we can use any size for
+// the fake viewport.
+const RECT VIEWPORT_DEFAULT_RECT = {0, 0, 1000, 1000};
- // TODO(ananta)
- // Remove the CHECK statements here and below and replace them with logs
- // when this code stabilizes.
+bool DirectManipulationHelper::Initialize(WindowEventTarget* event_target) {
+ // IDirectManipulationUpdateManager is the first COM object created by the
+ // application to retrieve other objects in the Direct Manipulation API.
+ // It also serves to activate and deactivate Direct Manipulation functionality
+ // on a per-HWND basis.
HRESULT hr =
::CoCreateInstance(CLSID_DirectManipulationManager, nullptr,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&manager_));
- CHECK(SUCCEEDED(hr));
+ if (!SUCCEEDED(hr))
+ return false;
- hr = ::CoCreateInstance(CLSID_DCompManipulationCompositor, nullptr,
- CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&compositor_));
- CHECK(SUCCEEDED(hr));
+ // Since we want to use fake viewport, we need UpdateManager to tell a fake
+ // fake render frame.
+ hr = manager_->GetUpdateManager(IID_PPV_ARGS(&update_manager_));
+ if (!SUCCEEDED(hr))
+ return false;
- hr = manager_->GetUpdateManager(IID_PPV_ARGS(update_manager_.GetAddressOf()));
- CHECK(SUCCEEDED(hr));
+ hr = manager_->CreateViewport(nullptr, window_, IID_PPV_ARGS(&viewport_));
+ if (!SUCCEEDED(hr))
+ return false;
- hr = compositor_->SetUpdateManager(update_manager_.Get());
- CHECK(SUCCEEDED(hr));
-
- hr = compositor_.CopyTo(frame_info_.GetAddressOf());
- CHECK(SUCCEEDED(hr));
-
- hr = manager_->CreateViewport(frame_info_.Get(), window,
- IID_PPV_ARGS(view_port_outer_.GetAddressOf()));
- CHECK(SUCCEEDED(hr));
-
- //
- // Enable the desired configuration for each viewport.
- //
DIRECTMANIPULATION_CONFIGURATION configuration =
DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
@@ -66,56 +102,360 @@ void DirectManipulationHelper::Initialize(HWND window) {
DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA |
DIRECTMANIPULATION_CONFIGURATION_RAILS_X |
DIRECTMANIPULATION_CONFIGURATION_RAILS_Y |
- DIRECTMANIPULATION_CONFIGURATION_SCALING |
- DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA;
+ DIRECTMANIPULATION_CONFIGURATION_SCALING;
+
+ hr = viewport_->ActivateConfiguration(configuration);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ // Since we are using fake viewport and only want to use Direct Manipulation
+ // for touchpad, we need to use MANUALUPDATE option.
+ hr = viewport_->SetViewportOptions(
+ DIRECTMANIPULATION_VIEWPORT_OPTIONS_MANUALUPDATE);
+ if (!SUCCEEDED(hr))
+ return false;
- hr = view_port_outer_->ActivateConfiguration(configuration);
- CHECK(SUCCEEDED(hr));
+ event_handler_ =
+ Microsoft::WRL::Make<DirectManipulationHandler>(this, event_target);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ // We got Direct Manipulation transform from
+ // IDirectManipulationViewportEventHandler.
+ hr = viewport_->AddEventHandler(window_, event_handler_.Get(),
+ &view_port_handler_cookie_);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ hr = viewport_->SetViewportRect(&VIEWPORT_DEFAULT_RECT);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ manager_->Activate(window_);
+
+ hr = viewport_->Enable();
+ update_manager_->Update(nullptr);
+ if (!SUCCEEDED(hr))
+ return false;
+
+ return true;
}
-void DirectManipulationHelper::SetBounds(const gfx::Rect& bounds) {
- Microsoft::WRL::ComPtr<IDirectManipulationPrimaryContent>
- primary_content_outer;
- HRESULT hr = view_port_outer_->GetPrimaryContent(
- IID_PPV_ARGS(primary_content_outer.GetAddressOf()));
- CHECK(SUCCEEDED(hr));
+void DirectManipulationHelper::Activate() {
+ manager_->Activate(window_);
+}
- Microsoft::WRL::ComPtr<IDirectManipulationContent> content_outer;
- hr = primary_content_outer.CopyTo(content_outer.GetAddressOf());
- CHECK(SUCCEEDED(hr));
+void DirectManipulationHelper::Deactivate() {
+ manager_->Deactivate(window_);
+}
- RECT rect = bounds.ToRECT();
+bool DirectManipulationHelper::OnPointerHitTest(
+ WPARAM w_param,
+ WindowEventTarget* event_target) {
+ // Update the device scale factor.
+ event_handler_->SetDeviceScaleFactor(
+ display::win::ScreenWin::GetScaleFactorForHWND(window_));
- hr = view_port_outer_->SetViewportRect(&rect);
- CHECK(SUCCEEDED(hr));
+ // Only DM_POINTERHITTEST can be the first message of input sequence of
+ // touchpad input.
+ // TODO(chaopeng) Check if Windows API changes:
+ // For WM_POINTER, the pointer type will show the event from mouse.
+ // For WM_POINTERACTIVATE, the pointer id will be different with the following
+ // message.
+ event_handler_->SetWindowEventTarget(event_target);
- hr = content_outer->SetContentRect(&rect);
- CHECK(SUCCEEDED(hr));
+ using GetPointerTypeFn = BOOL(WINAPI*)(UINT32, POINTER_INPUT_TYPE*);
+ UINT32 pointer_id = GET_POINTERID_WPARAM(w_param);
+ POINTER_INPUT_TYPE pointer_type;
+ static GetPointerTypeFn get_pointer_type = reinterpret_cast<GetPointerTypeFn>(
+ GetProcAddress(GetModuleHandleA("user32.dll"), "GetPointerType"));
+ if (get_pointer_type && get_pointer_type(pointer_id, &pointer_type) &&
+ pointer_type == PT_TOUCHPAD && event_target) {
+ viewport_->SetContact(pointer_id);
+ // Request begin frame for fake viewport.
+ need_poll_events_ = true;
+ }
+ return need_poll_events_;
}
-void DirectManipulationHelper::Activate(HWND window) {
- DCHECK(::IsWindow(window));
- manager_->Activate(window);
+HRESULT DirectManipulationHelper::ResetViewport(bool need_poll_events) {
+ // By zooming the primary content to a rect that match the viewport rect, we
+ // reset the content's transform to identity.
+ HRESULT hr = viewport_->ZoomToRect(
+ static_cast<float>(VIEWPORT_DEFAULT_RECT.left),
+ static_cast<float>(VIEWPORT_DEFAULT_RECT.top),
+ static_cast<float>(VIEWPORT_DEFAULT_RECT.right),
+ static_cast<float>(VIEWPORT_DEFAULT_RECT.bottom), FALSE);
+ if (!SUCCEEDED(hr))
+ return hr;
+
+ need_poll_events_ = need_poll_events;
+ return S_OK;
}
-void DirectManipulationHelper::Deactivate(HWND window) {
- DCHECK(::IsWindow(window));
- manager_->Deactivate(window);
+bool DirectManipulationHelper::PollForNextEvent() {
+ // Simulate 1 frame in update_manager_.
+ update_manager_->Update(nullptr);
+ return need_poll_events_;
}
-void DirectManipulationHelper::HandleMouseWheel(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- MSG msg = {window, message, w_param, l_param};
+void DirectManipulationHelper::SetDeviceScaleFactorForTesting(float factor) {
+ event_handler_->SetDeviceScaleFactor(factor);
+}
- HRESULT hr = view_port_outer_->SetContact(DIRECTMANIPULATION_MOUSEFOCUS);
- if (SUCCEEDED(hr)) {
- BOOL handled = FALSE;
- manager_->ProcessInput(&msg, &handled);
- view_port_outer_->ReleaseContact(DIRECTMANIPULATION_MOUSEFOCUS);
+// DirectManipulationHandler
+DirectManipulationHandler::DirectManipulationHandler() {
+ NOTREACHED();
+}
+
+DirectManipulationHandler::DirectManipulationHandler(
+ DirectManipulationHelper* helper,
+ WindowEventTarget* event_target)
+ : helper_(helper), event_target_(event_target) {}
+
+DirectManipulationHandler::~DirectManipulationHandler() {}
+
+void DirectManipulationHandler::TransitionToState(Gesture new_gesture_state) {
+ if (gesture_state_ == new_gesture_state)
+ return;
+
+ Gesture previous_gesture_state = gesture_state_;
+ gesture_state_ = new_gesture_state;
+
+ // End the previous sequence.
+ switch (previous_gesture_state) {
+ case Gesture::kScroll: {
+ // kScroll -> kNone, kPinch, ScrollEnd.
+ // kScroll -> kFling, we don't want to end the current scroll sequence.
+ if (new_gesture_state != Gesture::kFling)
+ event_target_->ApplyPanGestureScrollEnd();
+ break;
+ }
+ case Gesture::kFling: {
+ // kFling -> *, FlingEnd.
+ event_target_->ApplyPanGestureFlingEnd();
+ break;
+ }
+ case Gesture::kPinch: {
+ DCHECK_EQ(new_gesture_state, Gesture::kNone);
+ // kPinch -> kNone, PinchEnd. kPinch should only transition to kNone.
+ event_target_->ApplyPinchZoomEnd();
+ break;
+ }
+ case Gesture::kNone: {
+ // kNone -> *, no cleanup is needed.
+ break;
+ }
+ default:
+ NOTREACHED();
}
+
+ // Start the new sequence.
+ switch (new_gesture_state) {
+ case Gesture::kScroll: {
+ // kFling, kNone -> kScroll, ScrollBegin.
+ // ScrollBegin is different phase event with others. It must send within
+ // the first scroll event.
+ should_send_scroll_begin_ = true;
+ break;
+ }
+ case Gesture::kFling: {
+ // Only kScroll can transition to kFling.
+ DCHECK_EQ(previous_gesture_state, Gesture::kScroll);
+ event_target_->ApplyPanGestureFlingBegin();
+ break;
+ }
+ case Gesture::kPinch: {
+ // * -> kPinch, PinchBegin.
+ // Pinch gesture may begin with some scroll events.
+ event_target_->ApplyPinchZoomBegin();
+ break;
+ }
+ case Gesture::kNone: {
+ // * -> kNone, only cleanup is needed.
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+HRESULT DirectManipulationHandler::OnViewportStatusChanged(
+ IDirectManipulationViewport* viewport,
+ DIRECTMANIPULATION_STATUS current,
+ DIRECTMANIPULATION_STATUS previous) {
+ // MSDN never mention |viewport| are nullable and we never saw it is null when
+ // testing.
+ DCHECK(viewport);
+
+ // The state of our viewport has changed! We'l be in one of three states:
+ // - ENABLED: initial state
+ // - READY: the previous gesture has been completed
+ // - RUNNING: gesture updating
+ // - INERTIA: finger leave touchpad content still updating by inertia
+ HRESULT hr = S_OK;
+
+ // Windows should not call this when event_target_ is null since we do not
+ // pass the DM_POINTERHITTEST to DirectManipulation.
+ if (!event_target_)
+ return hr;
+
+ if (current == previous)
+ return hr;
+
+ if (current == DIRECTMANIPULATION_INERTIA) {
+ // Fling must lead by Scroll. We can actually hit here when user pinch then
+ // quickly pan gesture and leave touchpad. In this case, we don't want to
+ // start a new sequence until the gesture end. The rest events in sequence
+ // will be ignore since sequence still in pinch and only scale factor
+ // changes will be applied.
+ if (previous != DIRECTMANIPULATION_RUNNING ||
+ gesture_state_ != Gesture::kScroll) {
+ return hr;
+ }
+
+ TransitionToState(Gesture::kFling);
+ }
+
+ if (current == DIRECTMANIPULATION_RUNNING) {
+ // INERTIA -> RUNNING, should start a new sequence.
+ if (previous == DIRECTMANIPULATION_INERTIA)
+ TransitionToState(Gesture::kNone);
+ }
+
+ // Reset the viewport when we're idle, so the content transforms always start
+ // at identity.
+ if (current == DIRECTMANIPULATION_READY) {
+ // Every animation will receive 2 ready message, we should stop request
+ // compositor animation at the second ready.
+ first_ready_ = !first_ready_;
+ hr = helper_->ResetViewport(first_ready_);
+ last_scale_ = 1.0f;
+ last_x_offset_ = 0.0f;
+ last_y_offset_ = 0.0f;
+
+ TransitionToState(Gesture::kNone);
+ }
+
+ return hr;
+}
+
+HRESULT DirectManipulationHandler::OnViewportUpdated(
+ IDirectManipulationViewport* viewport) {
+ // Nothing to do here.
+ return S_OK;
+}
+
+namespace {
+
+bool FloatEquals(float f1, float f2) {
+ // The idea behind this is to use this fraction of the larger of the
+ // two numbers as the limit of the difference. This breaks down near
+ // zero, so we reuse this as the minimum absolute size we will use
+ // for the base of the scale too.
+ static const float epsilon_scale = 0.00001f;
+ return fabs(f1 - f2) <
+ epsilon_scale *
+ std::fmax(std::fmax(std::fabs(f1), std::fabs(f2)), epsilon_scale);
+}
+
+bool DifferentLessThanOne(int f1, int f2) {
+ return abs(f1 - f2) < 1;
+}
+
+} // namespace
+
+HRESULT DirectManipulationHandler::OnContentUpdated(
+ IDirectManipulationViewport* viewport,
+ IDirectManipulationContent* content) {
+ // MSDN never mention these params are nullable and we never saw they are null
+ // when testing.
+ DCHECK(viewport);
+ DCHECK(content);
+
+ HRESULT hr = S_OK;
+
+ // Windows should not call this when event_target_ is null since we do not
+ // pass the DM_POINTERHITTEST to DirectManipulation.
+ if (!event_target_)
+ return hr;
+
+ float xform[6];
+ hr = content->GetContentTransform(xform, ARRAYSIZE(xform));
+ if (!SUCCEEDED(hr))
+ return hr;
+
+ float scale = xform[0];
+ int x_offset = xform[4] / device_scale_factor_;
+ int y_offset = xform[5] / device_scale_factor_;
+
+ // Ignore if Windows pass scale=0 to us.
+ if (scale == 0.0f) {
+ LOG(ERROR) << "Windows DirectManipulation API pass scale = 0.";
+ return hr;
+ }
+
+ // Ignore the scale factor change less than float point rounding error and
+ // scroll offset change less than 1.
+ // TODO(456622) Because we don't fully support fractional scroll, pass float
+ // scroll offset feels steppy. eg.
+ // first x_offset is 0.1 ignored, but last_x_offset_ set to 0.1
+ // second x_offset is 1 but x_offset - last_x_offset_ is 0.9 ignored.
+ if (FloatEquals(scale, last_scale_) &&
+ DifferentLessThanOne(x_offset, last_x_offset_) &&
+ DifferentLessThanOne(y_offset, last_y_offset_)) {
+ return hr;
+ }
+
+ DCHECK_NE(last_scale_, 0.0f);
+
+ // DirectManipulation will send xy transform move to down-right which is noise
+ // when pinch zoom. We should consider the gesture either Scroll or Pinch at
+ // one sequence. But Pinch gesture may begin with some scroll transform since
+ // DirectManipulation recognition maybe wrong at start if the user pinch with
+ // slow motion. So we allow kScroll -> kPinch.
+
+ // Consider this is a Scroll when scale factor equals 1.0.
+ if (FloatEquals(scale, 1.0f)) {
+ if (gesture_state_ == Gesture::kNone)
+ TransitionToState(Gesture::kScroll);
+ } else {
+ // Pinch gesture may begin with some scroll events.
+ TransitionToState(Gesture::kPinch);
+ }
+
+ if (gesture_state_ == Gesture::kScroll) {
+ if (should_send_scroll_begin_) {
+ event_target_->ApplyPanGestureScrollBegin(x_offset - last_x_offset_,
+ y_offset - last_y_offset_);
+ should_send_scroll_begin_ = false;
+ } else {
+ event_target_->ApplyPanGestureScroll(x_offset - last_x_offset_,
+ y_offset - last_y_offset_);
+ }
+ } else if (gesture_state_ == Gesture::kFling) {
+ event_target_->ApplyPanGestureFling(x_offset - last_x_offset_,
+ y_offset - last_y_offset_);
+ } else {
+ event_target_->ApplyPinchZoomScale(scale / last_scale_);
+ }
+
+ last_scale_ = scale;
+ last_x_offset_ = x_offset;
+ last_y_offset_ = y_offset;
+
+ return hr;
+}
+
+void DirectManipulationHandler::SetWindowEventTarget(
+ WindowEventTarget* event_target) {
+ event_target_ = event_target;
+}
+
+void DirectManipulationHandler::SetDeviceScaleFactor(
+ float device_scale_factor) {
+ device_scale_factor_ = device_scale_factor;
}
-} // namespace win.
-} // namespace ui.
+} // namespace win
+} // namespace ui
diff --git a/chromium/ui/base/win/direct_manipulation.h b/chromium/ui/base/win/direct_manipulation.h
index af7ad807f2e..c0b603a7acf 100644
--- a/chromium/ui/base/win/direct_manipulation.h
+++ b/chromium/ui/base/win/direct_manipulation.h
@@ -5,79 +5,150 @@
#ifndef UI_WIN_DIRECT_MANIPULATION_H_
#define UI_WIN_DIRECT_MANIPULATION_H_
-#include <directmanipulation.h>
-#include <wrl/client.h>
+#include <windows.h>
+#include <directmanipulation.h>
+#include <wrl.h>
#include <memory>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "ui/base/ui_base_export.h"
+#include "ui/base/win/window_event_target.h"
#include "ui/gfx/geometry/rect.h"
+namespace content {
+class DirectManipulationBrowserTest;
+} // namespace content
+
namespace ui {
namespace win {
+class DirectManipulationUnitTest;
+
+class DirectManipulationHelper;
+
+// DirectManipulationHandler receives status update and gesture events from
+// Direct Manipulation API.
+class DirectManipulationHandler
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::Implements<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::FtmBase,
+ IDirectManipulationViewportEventHandler>> {
+ public:
+ explicit DirectManipulationHandler(DirectManipulationHelper* helper,
+ WindowEventTarget* event_target);
+
+ // WindowEventTarget updates for every DM_POINTERHITTEST in case window
+ // hierarchy changed.
+ void SetWindowEventTarget(WindowEventTarget* event_target);
+
+ void SetDeviceScaleFactor(float device_scale_factor);
+
+ private:
+ friend DirectManipulationUnitTest;
+
+ DirectManipulationHandler();
+ ~DirectManipulationHandler() override;
+
+ enum class Gesture { kNone, kScroll, kFling, kPinch };
+
+ void TransitionToState(Gesture gesture);
+
+ HRESULT STDMETHODCALLTYPE
+ OnViewportStatusChanged(_In_ IDirectManipulationViewport* viewport,
+ _In_ DIRECTMANIPULATION_STATUS current,
+ _In_ DIRECTMANIPULATION_STATUS previous) override;
+
+ HRESULT STDMETHODCALLTYPE
+ OnViewportUpdated(_In_ IDirectManipulationViewport* viewport) override;
+
+ HRESULT STDMETHODCALLTYPE
+ OnContentUpdated(_In_ IDirectManipulationViewport* viewport,
+ _In_ IDirectManipulationContent* content) override;
+
+ DirectManipulationHelper* helper_ = nullptr;
+ WindowEventTarget* event_target_ = nullptr;
+ float device_scale_factor_ = 1.0f;
+ float last_scale_ = 1.0f;
+ int last_x_offset_ = 0;
+ int last_y_offset_ = 0;
+ bool first_ready_ = false;
+ bool should_send_scroll_begin_ = false;
+
+ // Current recognized gesture from Direct Manipulation.
+ Gesture gesture_state_ = Gesture::kNone;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectManipulationHandler);
+};
+
// Windows 10 provides a new API called Direct Manipulation which generates
-// smooth scroll events via WM_MOUSEWHEEL messages with predictable deltas
-// on high precision touch pads. This basically requires the application window
-// to register as a Direct Manipulation consumer. The way mouse wheel messages
-// are dispatched is
+// smooth scroll and scale factor via IDirectManipulationViewportEventHandler
+// on precision touchpad.
// 1. The foreground window is checked to see if it is a Direct Manipulation
// consumer.
-// 2. If it is then Direct Manipulation takes over and sends the following
-// messages. WM_POINTERACTIVATE, WM_POINTERDOWN and DM_POINTERHITTEST.
-// 3. It then posts WM_MOUSEWHEEL messages with precision deltas which vary
-// based on the amount of the scroll.
-// 4. If the foreground window is not a Direct Manipulation consumer, it
-// then takes a fallback route where it posts WM_MOUSEWHEEL messages
-// with precision but varying deltas to the window. There is a also
-// a slight delay in receiving the first set of mouse wheel messages.
-// This causes scrolling to appear janky and jumpy.
-// Our approach for addressing this is to do the absolute minimum to
-// register our window as a Direct Manipulation consumer. This class
-// provides the necessary functionality to register the passed in HWND as a
-// Direct Manipulation consumer. We don't rely on Direct manipulation
-// to do the smooth scrolling in the background thread as documented on
-// msdn.
+// 2. Call SetContact in Direct Manipulation takes over the following scrolling
+// when DM_POINTERHITTEST.
+// 3. OnViewportStatusChanged will be called when the gesture phase change.
+// OnContentUpdated will be called when the gesture update.
class UI_BASE_EXPORT DirectManipulationHelper {
public:
- // Creates an instance of this class if Direct Manipulation is enabled on
- // the platform. If not returns NULL.
- static std::unique_ptr<DirectManipulationHelper> CreateInstance();
-
- // This function instantiates Direct Manipulation and creates a viewport for
- // the passed in |window|.
- // consumer. Most of the code is boiler plate and is based on the sample.
- void Initialize(HWND window);
+ // Creates and initializes an instance of this class if Direct Manipulation is
+ // enabled on the platform. Returns nullptr if it disabled or failed on
+ // initialization.
+ static std::unique_ptr<DirectManipulationHelper> CreateInstance(
+ HWND window,
+ WindowEventTarget* event_target);
+
+ // Creates and initializes an instance for testing.
+ static std::unique_ptr<DirectManipulationHelper> CreateInstanceForTesting(
+ WindowEventTarget* event_target,
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport);
- // Sets the bounds of the fake Direct manipulation viewport to match those
- // of the legacy window.
- void SetBounds(const gfx::Rect& bounds);
+ ~DirectManipulationHelper();
// Registers and activates the passed in |window| as a Direct Manipulation
// consumer.
- void Activate(HWND window);
+ void Activate();
// Deactivates Direct Manipulation processing on the passed in |window|.
- void Deactivate(HWND window);
+ void Deactivate();
- // Passes the WM_MOUSEWHEEL messages to Direct Manipulation. This is for
- // logistics purposes.
- void HandleMouseWheel(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param);
+ // Reset the fake viewport for gesture end.
+ HRESULT ResetViewport(bool need_animtation);
- ~DirectManipulationHelper();
+ // Pass the pointer hit test to Direct Manipulation. Return true indicated we
+ // need poll for new events every frame from here.
+ bool OnPointerHitTest(WPARAM w_param, WindowEventTarget* event_target);
+
+ // On each frame poll new Direct Manipulation events. Return true if we still
+ // need poll for new events on next frame, otherwise stop request need begin
+ // frame.
+ bool PollForNextEvent();
private:
+ friend class content::DirectManipulationBrowserTest;
+ friend class DirectManipulationUnitTest;
+
DirectManipulationHelper();
- Microsoft::WRL::ComPtr<IDirectManipulationManager2> manager_;
- Microsoft::WRL::ComPtr<IDirectManipulationCompositor> compositor_;
+ // This function instantiates Direct Manipulation and creates a viewport for
+ // the passed in |window|. Return false if initialize failed.
+ bool Initialize(WindowEventTarget* event_target);
+
+ void SetDeviceScaleFactorForTesting(float factor);
+
+ Microsoft::WRL::ComPtr<IDirectManipulationManager> manager_;
Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> update_manager_;
- Microsoft::WRL::ComPtr<IDirectManipulationFrameInfoProvider> frame_info_;
- Microsoft::WRL::ComPtr<IDirectManipulationViewport2> view_port_outer_;
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport_;
+ Microsoft::WRL::ComPtr<DirectManipulationHandler> event_handler_;
+ HWND window_;
+ DWORD view_port_handler_cookie_;
+ bool need_poll_events_ = false;
DISALLOW_COPY_AND_ASSIGN(DirectManipulationHelper);
};
diff --git a/chromium/ui/base/win/direct_manipulation_unittest.cc b/chromium/ui/base/win/direct_manipulation_unittest.cc
new file mode 100644
index 00000000000..79d4bb77502
--- /dev/null
+++ b/chromium/ui/base/win/direct_manipulation_unittest.cc
@@ -0,0 +1,756 @@
+// 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/win/direct_manipulation.h"
+
+#include <objbase.h>
+
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_features.h"
+
+namespace ui {
+
+namespace win {
+
+namespace {
+
+class MockDirectManipulationViewport
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::Implements<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::FtmBase,
+ IDirectManipulationViewport>> {
+ public:
+ MockDirectManipulationViewport() {}
+
+ ~MockDirectManipulationViewport() override {}
+
+ HRESULT STDMETHODCALLTYPE Enable() override { return S_OK; }
+
+ HRESULT STDMETHODCALLTYPE Disable() override { return S_OK; }
+
+ HRESULT STDMETHODCALLTYPE SetContact(_In_ UINT32 pointerId) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE ReleaseContact(_In_ UINT32 pointerId) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE ReleaseAllContacts() override { return S_OK; }
+
+ HRESULT STDMETHODCALLTYPE
+ GetStatus(_Out_ DIRECTMANIPULATION_STATUS* status) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetTag(_In_ REFIID riid,
+ _COM_Outptr_opt_ void** object,
+ _Out_opt_ UINT32* id) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE SetTag(_In_opt_ IUnknown* object,
+ _In_ UINT32 id) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetViewportRect(_Out_ RECT* viewport) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetViewportRect(_In_ const RECT* viewport) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE ZoomToRect(_In_ const float left,
+ _In_ const float top,
+ _In_ const float right,
+ _In_ const float bottom,
+ _In_ BOOL animate) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetViewportTransform(_In_reads_(point_count) const float* matrix,
+ _In_ DWORD point_count) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SyncDisplayTransform(_In_reads_(point_count) const float* matrix,
+ _In_ DWORD point_count) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ GetPrimaryContent(_In_ REFIID riid, _COM_Outptr_ void** object) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ AddContent(_In_ IDirectManipulationContent* content) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ RemoveContent(_In_ IDirectManipulationContent* content) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE SetViewportOptions(
+ _In_ DIRECTMANIPULATION_VIEWPORT_OPTIONS options) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE AddConfiguration(
+ _In_ DIRECTMANIPULATION_CONFIGURATION configuration) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE RemoveConfiguration(
+ _In_ DIRECTMANIPULATION_CONFIGURATION configuration) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE ActivateConfiguration(
+ _In_ DIRECTMANIPULATION_CONFIGURATION configuration) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE SetManualGesture(
+ _In_ DIRECTMANIPULATION_GESTURE_CONFIGURATION configuration) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetChaining(_In_ DIRECTMANIPULATION_MOTION_TYPES enabledTypes) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ AddEventHandler(_In_opt_ HWND window,
+ _In_ IDirectManipulationViewportEventHandler* eventHandler,
+ _Out_ DWORD* cookie) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE RemoveEventHandler(_In_ DWORD cookie) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetInputMode(_In_ DIRECTMANIPULATION_INPUT_MODE mode) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetUpdateMode(_In_ DIRECTMANIPULATION_INPUT_MODE mode) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE Stop() override { return S_OK; }
+
+ HRESULT STDMETHODCALLTYPE Abandon() override { return S_OK; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDirectManipulationViewport);
+};
+
+class MockDirectManipulationContent
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::Implements<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::FtmBase,
+ IDirectManipulationContent>> {
+ public:
+ MockDirectManipulationContent() {}
+
+ ~MockDirectManipulationContent() override {}
+
+ void SetContentTransform(float scale, float scroll_x, float scroll_y) {
+ for (int i = 0; i < 6; ++i)
+ transforms_[i] = 0;
+ transforms_[0] = scale;
+ transforms_[4] = scroll_x;
+ transforms_[5] = scroll_y;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ GetContentTransform(_Out_writes_(point_count) float* transforms,
+ _In_ DWORD point_count) override {
+ for (int i = 0; i < 6; ++i)
+ transforms[i] = transforms_[i];
+ return S_OK;
+ }
+
+ // Other Overrides
+ HRESULT STDMETHODCALLTYPE GetContentRect(_Out_ RECT* contentSize) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SetContentRect(_In_ const RECT* contentSize) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetViewport(_In_ REFIID riid,
+ _COM_Outptr_ void** object) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetTag(_In_ REFIID riid,
+ _COM_Outptr_opt_ void** object,
+ _Out_opt_ UINT32* id) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE SetTag(_In_opt_ IUnknown* object,
+ _In_ UINT32 id) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ GetOutputTransform(_Out_writes_(point_count) float* matrix,
+ _In_ DWORD point_count) override {
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ SyncContentTransform(_In_reads_(point_count) const float* matrix,
+ _In_ DWORD point_count) override {
+ return S_OK;
+ }
+
+ private:
+ float transforms_[6];
+
+ DISALLOW_COPY_AND_ASSIGN(MockDirectManipulationContent);
+};
+
+enum class EventGesture {
+ kScrollBegin,
+ kScroll,
+ kScrollEnd,
+ kFlingBegin,
+ kFling,
+ kFlingEnd,
+ kScaleBegin,
+ kScale,
+ kScaleEnd,
+};
+
+struct Event {
+ explicit Event(float scale) : gesture_(EventGesture::kScale), scale_(scale) {}
+
+ Event(EventGesture gesture, float scroll_x, float scroll_y)
+ : gesture_(gesture), scroll_x_(scroll_x), scroll_y_(scroll_y) {}
+
+ explicit Event(EventGesture gesture) : gesture_(gesture) {}
+
+ EventGesture gesture_;
+ float scale_ = 0;
+ float scroll_x_ = 0;
+ float scroll_y_ = 0;
+};
+
+class MockWindowEventTarget : public WindowEventTarget {
+ public:
+ MockWindowEventTarget() {}
+
+ ~MockWindowEventTarget() override {}
+
+ void ApplyPinchZoomScale(float scale) override {
+ events_.push_back(Event(scale));
+ }
+
+ void ApplyPinchZoomBegin() override {
+ events_.push_back(Event(EventGesture::kScaleBegin));
+ }
+
+ void ApplyPinchZoomEnd() override {
+ events_.push_back(Event(EventGesture::kScaleEnd));
+ }
+
+ void ApplyPanGestureScroll(int scroll_x, int scroll_y) override {
+ events_.push_back(Event(EventGesture::kScroll, scroll_x, scroll_y));
+ }
+
+ void ApplyPanGestureFling(int scroll_x, int scroll_y) override {
+ events_.push_back(Event(EventGesture::kFling, scroll_x, scroll_y));
+ }
+
+ void ApplyPanGestureScrollBegin(int scroll_x, int scroll_y) override {
+ events_.push_back(Event(EventGesture::kScrollBegin, scroll_x, scroll_y));
+ }
+
+ void ApplyPanGestureFlingBegin() override {
+ events_.push_back(Event(EventGesture::kFlingBegin));
+ }
+
+ void ApplyPanGestureFlingEnd() override {
+ events_.push_back(Event(EventGesture::kFlingEnd));
+ }
+
+ void ApplyPanGestureScrollEnd() override {
+ events_.push_back(Event(EventGesture::kScrollEnd));
+ }
+
+ std::vector<Event> GetEvents() {
+ std::vector<Event> result = events_;
+ events_.clear();
+ return result;
+ }
+
+ // Other Overrides
+ LRESULT HandleMouseMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ LRESULT HandlePointerMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ LRESULT HandleKeyboardMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ LRESULT HandleTouchMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ LRESULT HandleScrollMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ LRESULT HandleNcHitTestMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool* handled) override {
+ return S_OK;
+ }
+
+ void HandleParentChanged() override {}
+
+ private:
+ std::vector<Event> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockWindowEventTarget);
+};
+
+} // namespace
+
+class DirectManipulationUnitTest : public testing::Test {
+ public:
+ DirectManipulationUnitTest() {
+ scoped_feature_list_.InitAndEnableFeature(features::kPrecisionTouchpad);
+
+ viewport_ = Microsoft::WRL::Make<MockDirectManipulationViewport>();
+ content_ = Microsoft::WRL::Make<MockDirectManipulationContent>();
+ direct_manipulation_helper_ =
+ DirectManipulationHelper::CreateInstanceForTesting(&event_target_,
+ viewport_);
+ }
+
+ ~DirectManipulationUnitTest() override {}
+
+ DirectManipulationHelper* GetDirectManipulationHelper() {
+ return direct_manipulation_helper_.get();
+ }
+
+ std::vector<Event> GetEvents() { return event_target_.GetEvents(); }
+
+ void ViewportStatusChanged(DIRECTMANIPULATION_STATUS current,
+ DIRECTMANIPULATION_STATUS previous) {
+ direct_manipulation_helper_->event_handler_->OnViewportStatusChanged(
+ viewport_.Get(), current, previous);
+ }
+
+ void ContentUpdated(float scale, float scroll_x, float scroll_y) {
+ content_->SetContentTransform(scale, scroll_x, scroll_y);
+ direct_manipulation_helper_->event_handler_->OnContentUpdated(
+ viewport_.Get(), content_.Get());
+ }
+
+ void SetNeedAnimation(bool need_poll_events) {
+ direct_manipulation_helper_->need_poll_events_ = need_poll_events;
+ }
+
+ bool NeedAnimation() {
+ return direct_manipulation_helper_->need_poll_events_;
+ }
+
+ void SetDeviceScaleFactor(float factor) {
+ direct_manipulation_helper_->SetDeviceScaleFactorForTesting(factor);
+ }
+
+ private:
+ std::unique_ptr<DirectManipulationHelper> direct_manipulation_helper_;
+ Microsoft::WRL::ComPtr<MockDirectManipulationViewport> viewport_;
+ Microsoft::WRL::ComPtr<MockDirectManipulationContent> content_;
+ MockWindowEventTarget event_target_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectManipulationUnitTest);
+};
+
+TEST_F(DirectManipulationUnitTest, HelperShouldCreateForWin10) {
+ // We should create DirectManipulationHelper instance when win version >= 10.
+ EXPECT_EQ(GetDirectManipulationHelper() != nullptr,
+ base::win::GetVersion() >= base::win::VERSION_WIN10);
+}
+
+TEST_F(DirectManipulationUnitTest, ReceiveSimplePanTransform) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_READY);
+ ContentUpdated(1, 10, 0);
+
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+ EXPECT_EQ(10, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ // For next update, should only apply the difference.
+ ContentUpdated(1, 15, 0);
+
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScroll, events[0].gesture_);
+ EXPECT_EQ(5, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_RUNNING);
+
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollEnd, events[0].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, ReceivePanFling) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_READY);
+ ContentUpdated(1, 10, 0);
+
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+ EXPECT_EQ(10, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ // For next update, should only apply the difference.
+ ContentUpdated(1, 15, 0);
+
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScroll, events[0].gesture_);
+ EXPECT_EQ(5, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ // Fling Begin.
+ ViewportStatusChanged(DIRECTMANIPULATION_INERTIA, DIRECTMANIPULATION_RUNNING);
+
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingBegin, events[0].gesture_);
+
+ ContentUpdated(1, 20, 0);
+
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFling, events[0].gesture_);
+ EXPECT_EQ(5, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_INERTIA);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingEnd, events[0].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, ReceiveSimpleScaleTransform) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_READY);
+ ContentUpdated(1.1f, 0, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(EventGesture::kScaleBegin, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScale, events[1].gesture_);
+ EXPECT_EQ(1.1f, events[1].scale_);
+
+ // For next update, should only apply the difference.
+ ContentUpdated(1.21f, 0, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScale, events[0].gesture_);
+ EXPECT_EQ(1.1f, events[0].scale_);
+
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_RUNNING);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScaleEnd, events[0].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, ReceiveScrollTransformLessThanOne) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Scroll offset less than 1, should not apply.
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_READY);
+ ContentUpdated(1, 0.1f, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(0u, events.size());
+
+ // Scroll offset less than 1, should not apply.
+ ContentUpdated(1, 0.2f, 0);
+ events = GetEvents();
+ EXPECT_EQ(0u, events.size());
+
+ // Scroll offset more than 1, should only apply integer part.
+ ContentUpdated(1, 1.2f, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+ EXPECT_EQ(1, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+
+ // Scroll offset difference less than 1, should not apply.
+ ContentUpdated(1, 1.5f, 0);
+ events = GetEvents();
+ EXPECT_EQ(0u, events.size());
+
+ // Scroll offset difference more than 1, should only apply integer part.
+ ContentUpdated(1, 3.0f, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScroll, events[0].gesture_);
+ EXPECT_EQ(2, events[0].scroll_x_);
+ EXPECT_EQ(0, events[0].scroll_y_);
+}
+
+TEST_F(DirectManipulationUnitTest,
+ ReceiveScaleTransformLessThanFloatPointError) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Scale factor less than float point error, ignore.
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_READY);
+ ContentUpdated(1.000001f, 0, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(0u, events.size());
+
+ // Scale factor more than float point error, apply.
+ ContentUpdated(1.00001f, 0, 0);
+ events = GetEvents();
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(EventGesture::kScaleBegin, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScale, events[1].gesture_);
+ EXPECT_EQ(1.00001f, events[1].scale_);
+
+ // Scale factor difference less than float point error, ignore.
+ ContentUpdated(1.000011f, 0, 0);
+ events = GetEvents();
+ EXPECT_EQ(0u, events.size());
+
+ // Scale factor difference more than float point error, apply.
+ ContentUpdated(1.000021f, 0, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScale, events[0].gesture_);
+ EXPECT_EQ(1.000021f / 1.00001f, events[0].scale_);
+
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_RUNNING);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScaleEnd, events[0].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, InSameSequenceReceiveBothScrollAndScale) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Direct Manipulation maybe give incorrect predictions. In this case, we will
+ // receive scroll first then scale after.
+
+ // First event is a scroll event.
+ ContentUpdated(1.0f, 5, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+
+ // Second event comes with scale factor. Now the scroll offset only noise.
+ ContentUpdated(1.00001f, 5, 0);
+ events = GetEvents();
+ EXPECT_EQ(3u, events.size());
+ EXPECT_EQ(EventGesture::kScrollEnd, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScaleBegin, events[1].gesture_);
+ EXPECT_EQ(EventGesture::kScale, events[2].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, InSameSequenceReceiveScaleAfterFling) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Direct Manipulation maybe give pinch event after fling. In this case, we
+ // should end the current sequence first.
+
+ // First event is a scroll event.
+ ContentUpdated(1.0f, 5, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+
+ // Fling Begin.
+ ViewportStatusChanged(DIRECTMANIPULATION_INERTIA, DIRECTMANIPULATION_RUNNING);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingBegin, events[0].gesture_);
+
+ ContentUpdated(1, 10, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFling, events[0].gesture_);
+
+ // Event comes with scale factor. Now the scroll offset only noise.
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_INERTIA);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingEnd, events[0].gesture_);
+
+ ContentUpdated(1.00001f, 10, 0);
+ events = GetEvents();
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(EventGesture::kScaleBegin, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScale, events[1].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest, InSameSequenceReceiveScrollAfterFling) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Direct Manipulation maybe give scroll event after fling. In this case, we
+ // should end the current sequence first.
+
+ // First event is a scroll event.
+ ContentUpdated(1.0f, 5, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+
+ // Fling Begin.
+ ViewportStatusChanged(DIRECTMANIPULATION_INERTIA, DIRECTMANIPULATION_RUNNING);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingBegin, events[0].gesture_);
+
+ ContentUpdated(1, 10, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFling, events[0].gesture_);
+
+ // Fling back to Scroll.
+ ViewportStatusChanged(DIRECTMANIPULATION_RUNNING, DIRECTMANIPULATION_INERTIA);
+ ContentUpdated(1, 15, 0);
+ events = GetEvents();
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(EventGesture::kFlingEnd, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScrollBegin, events[1].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest,
+ ReceiveScaleAfterFlingWithoutViewportStatusChanged) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // We never see this when testing, but still what to test it.
+
+ ContentUpdated(1.0f, 5, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+
+ // Fling Begin.
+ ViewportStatusChanged(DIRECTMANIPULATION_INERTIA, DIRECTMANIPULATION_RUNNING);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFlingBegin, events[0].gesture_);
+
+ ContentUpdated(1, 10, 0);
+ events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kFling, events[0].gesture_);
+
+ // Event comes with scale factor. But no ViewportStatusChanged.
+ ContentUpdated(1.00001f, 10, 0);
+ events = GetEvents();
+ EXPECT_EQ(3u, events.size());
+ EXPECT_EQ(EventGesture::kFlingEnd, events[0].gesture_);
+ EXPECT_EQ(EventGesture::kScaleBegin, events[1].gesture_);
+ EXPECT_EQ(EventGesture::kScale, events[2].gesture_);
+}
+
+TEST_F(DirectManipulationUnitTest,
+ NeedAnimtationShouldBeFalseAfterSecondReset) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ // Direct Manipulation will set need_poll_events_ true when DM_POINTERTEST
+ // from touchpad.
+ SetNeedAnimation(true);
+
+ // Receive first ready when gesture end.
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_RUNNING);
+ EXPECT_TRUE(NeedAnimation());
+
+ // Receive second ready from ZoomToRect.
+ ViewportStatusChanged(DIRECTMANIPULATION_READY, DIRECTMANIPULATION_RUNNING);
+ EXPECT_FALSE(NeedAnimation());
+}
+
+TEST_F(DirectManipulationUnitTest, HiDPIScroll) {
+ if (!GetDirectManipulationHelper())
+ return;
+
+ SetDeviceScaleFactor(10.0);
+ ContentUpdated(1.0f, 50, 0);
+ std::vector<Event> events = GetEvents();
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(EventGesture::kScrollBegin, events[0].gesture_);
+ EXPECT_EQ(5, events[0].scroll_x_);
+}
+
+} // namespace win
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h
deleted file mode 100644
index b5392c4b686..00000000000
--- a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
-#define UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/base/ui_base_export.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace ui {
-
-class OnScreenKeyboardDetector;
-class OnScreenKeyboardObserver;
-
-// This class provides functionality to display the on screen keyboard on
-// Windows 8+. It optionally notifies observers that the OSK is displayed,
-// hidden, etc.
-class UI_BASE_EXPORT OnScreenKeyboardDisplayManager {
- public:
- static OnScreenKeyboardDisplayManager* GetInstance();
-
- ~OnScreenKeyboardDisplayManager();
-
- // Functions to display and dismiss the keyboard.
- // The optional |observer| parameter allows callers to be notified when the
- // keyboard is displayed, dismissed, etc.
- bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer);
- // When the keyboard is dismissed, the registered observer if any is removed
- // after notifying it.
- bool DismissVirtualKeyboard();
-
- // Removes a registered observer.
- void RemoveObserver(OnScreenKeyboardObserver* observer);
-
- // 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);
-
- // Returns true if the virtual keyboard is currently visible.
- bool IsKeyboardVisible() const;
-
- private:
- OnScreenKeyboardDisplayManager();
-
- std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_;
-
- // The location of TabTip.exe.
- base::string16 osk_path_;
-
- DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManager);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_
diff --git a/chromium/ui/base/win/osk_display_manager.cc b/chromium/ui/base/win/osk_display_manager.cc
deleted file mode 100644
index bbce7bda6eb..00000000000
--- a/chromium/ui/base/win/osk_display_manager.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/win/osk_display_manager.h"
-
-#include <windows.h>
-#include <shellapi.h>
-#include <shlobj.h>
-#include <shobjidl.h> // Must be before propkey.
-
-#include "base/bind.h"
-#include "base/debug/leak_annotations.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/win/registry.h"
-#include "base/win/scoped_co_mem.h"
-#include "base/win/win_util.h"
-#include "base/win/windows_version.h"
-#include "ui/base/win/hidden_window.h"
-#include "ui/base/win/osk_display_observer.h"
-#include "ui/display/win/dpi.h"
-#include "ui/gfx/geometry/dip_util.h"
-
-namespace {
-
-constexpr int kCheckOSKDelayMs = 1000;
-constexpr int kDismissKeyboardRetryTimeoutMs = 100;
-constexpr int kDismissKeyboardMaxRetries = 5;
-
-constexpr wchar_t kOSKClassName[] = L"IPTip_Main_Window";
-
-constexpr wchar_t kWindows8OSKRegPath[] =
- L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
- L"\\LocalServer32";
-
-} // namespace
-
-namespace ui {
-
-// This class provides functionality to detect when the on screen keyboard
-// is displayed and move the main window up if it is obscured by the keyboard.
-class OnScreenKeyboardDetector {
- public:
- OnScreenKeyboardDetector();
- ~OnScreenKeyboardDetector();
-
- // Schedules a delayed task which detects if the on screen keyboard was
- // displayed.
- void DetectKeyboard(HWND main_window);
-
- // Dismisses the on screen keyboard. If a call to display the keyboard was
- // made, this function waits for the keyboard to become visible by retrying
- // upto a maximum of kDismissKeyboardMaxRetries.
- bool DismissKeyboard();
-
- // Add/Remove keyboard observers.
- // Please note that this class does not track the |observer| destruction. It
- // is upto the classes which set up these observers to remove them when they
- // are destroyed.
- void AddObserver(OnScreenKeyboardObserver* observer);
- void RemoveObserver(OnScreenKeyboardObserver* observer);
-
- // Returns true if the osk is visible. Sets osk bounding rect if non-null
- static bool IsKeyboardVisible(gfx::Rect* osk_bounding_rect);
-
- private:
- // Executes as a task and detects if the on screen keyboard is displayed.
- // Once the keyboard is displayed it schedules the HideIfNecessary() task to
- // detect when the keyboard is or should be hidden.
- void CheckIfKeyboardVisible();
-
- // Executes as a task and detects if the keyboard was hidden or should be
- // hidden.
- void HideIfNecessary();
-
- // Notifies observers that the keyboard was displayed.
- // A recurring task HideIfNecessary() is started to detect when the OSK
- // disappears.
- void HandleKeyboardVisible();
-
- // Notifies observers that the keyboard was hidden.
- // The observer list is cleared out after this notification.
- void HandleKeyboardHidden();
-
- // Removes all observers from the list.
- void ClearObservers();
-
- // The main window which displays the on screen keyboard.
- HWND main_window_ = nullptr;
-
- // Tracks if the keyboard was displayed.
- bool osk_visible_notification_received_ = false;
-
- // The keyboard dimensions in pixels.
- gfx::Rect osk_rect_pixels_;
-
- // Set to true if a call to DetectKeyboard() was made.
- bool keyboard_detect_requested_ = false;
-
- // Contains the number of attempts made to dismiss the keyboard. Please refer
- // to the DismissKeyboard() function for more information.
- int keyboard_dismiss_retry_count_ = 0;
-
- base::ObserverList<OnScreenKeyboardObserver, false> observers_;
-
- // Should be the last member in the class. Helps ensure that tasks spawned
- // by this class instance are canceled when it is destroyed.
- base::WeakPtrFactory<OnScreenKeyboardDetector> keyboard_detector_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDetector);
-};
-
-// OnScreenKeyboardDetector member definitions.
-OnScreenKeyboardDetector::OnScreenKeyboardDetector()
- : keyboard_detector_factory_(this) {}
-
-OnScreenKeyboardDetector::~OnScreenKeyboardDetector() {
- ClearObservers();
-}
-
-void OnScreenKeyboardDetector::DetectKeyboard(HWND main_window) {
- main_window_ = main_window;
- keyboard_detect_requested_ = true;
- // The keyboard is displayed by TabTip.exe which is launched via a
- // ShellExecute call in the
- // OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard() function. We use
- // a delayed task to check if the keyboard is visible because of the possible
- // delay between the ShellExecute call and the keyboard becoming visible.
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::CheckIfKeyboardVisible,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
-}
-
-bool OnScreenKeyboardDetector::DismissKeyboard() {
- // We dismiss the virtual keyboard by generating the ESC keystroke
- // programmatically.
- HWND osk = ::FindWindow(kOSKClassName, nullptr);
- if (::IsWindow(osk) && ::IsWindowEnabled(osk)) {
- keyboard_detect_requested_ = false;
- keyboard_dismiss_retry_count_ = 0;
- HandleKeyboardHidden();
- PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0);
- return true;
- } else if (keyboard_detect_requested_) {
- if (keyboard_dismiss_retry_count_ < kDismissKeyboardMaxRetries) {
- keyboard_dismiss_retry_count_++;
- // Please refer to the comments in the DetectKeyboard() function for more
- // information as to why we need a delayed task here.
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(base::IgnoreResult(
- &OnScreenKeyboardDetector::DismissKeyboard),
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kDismissKeyboardRetryTimeoutMs));
- } else {
- keyboard_dismiss_retry_count_ = 0;
- }
- }
- return false;
-}
-
-void OnScreenKeyboardDetector::AddObserver(OnScreenKeyboardObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void OnScreenKeyboardDetector::RemoveObserver(
- OnScreenKeyboardObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-// static
-bool OnScreenKeyboardDetector::IsKeyboardVisible(gfx::Rect* osk_bounding_rect) {
- HWND osk = ::FindWindow(kOSKClassName, nullptr);
- if (!::IsWindow(osk))
- return false;
- if (osk_bounding_rect) {
- RECT osk_rect = {};
- ::GetWindowRect(osk, &osk_rect);
- *osk_bounding_rect = gfx::Rect(osk_rect);
- }
- return ::IsWindowVisible(osk) && ::IsWindowEnabled(osk);
-}
-
-void OnScreenKeyboardDetector::CheckIfKeyboardVisible() {
- if (IsKeyboardVisible(&osk_rect_pixels_)) {
- if (!osk_visible_notification_received_)
- HandleKeyboardVisible();
- } else {
- DVLOG(1) << "OSK did not come up in 1 second. Something wrong.";
- }
-}
-
-void OnScreenKeyboardDetector::HideIfNecessary() {
- HWND osk = ::FindWindow(kOSKClassName, nullptr);
- if (!::IsWindow(osk))
- return;
-
- // Three cases here.
- // 1. OSK was hidden because the user dismissed it.
- // 2. We are no longer in the foreground.
- // 3. The OSK is still visible.
- // In the first case we just have to notify the observers that the OSK was
- // hidden.
- // In the second case we need to dismiss the OSK which internally will
- // notify the observers about the OSK being hidden.
- if (!::IsWindowEnabled(osk)) {
- if (osk_visible_notification_received_) {
- if (main_window_ == ::GetForegroundWindow()) {
- DVLOG(1) << "OSK window hidden while we are in the foreground.";
- HandleKeyboardHidden();
- }
- }
- } else if (main_window_ != ::GetForegroundWindow()) {
- if (osk_visible_notification_received_) {
- DVLOG(1) << "We are no longer in the foreground. Dismising OSK.";
- DismissKeyboard();
- }
- } else {
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
- }
-}
-
-void OnScreenKeyboardDetector::HandleKeyboardVisible() {
- DCHECK(!osk_visible_notification_received_);
- osk_visible_notification_received_ = true;
-
- for (OnScreenKeyboardObserver& observer : observers_)
- observer.OnKeyboardVisible(osk_rect_pixels_);
-
- // Now that the keyboard is visible, run the task to detect if it was hidden.
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary,
- keyboard_detector_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
-}
-
-void OnScreenKeyboardDetector::HandleKeyboardHidden() {
- osk_visible_notification_received_ = false;
- for (OnScreenKeyboardObserver& observer : observers_)
- observer.OnKeyboardHidden(osk_rect_pixels_);
- ClearObservers();
-}
-
-void OnScreenKeyboardDetector::ClearObservers() {
- for (auto& observer : observers_)
- RemoveObserver(&observer);
-}
-
-// OnScreenKeyboardDisplayManager member definitions.
-OnScreenKeyboardDisplayManager::OnScreenKeyboardDisplayManager() {}
-
-OnScreenKeyboardDisplayManager::~OnScreenKeyboardDisplayManager() {}
-
-OnScreenKeyboardDisplayManager* OnScreenKeyboardDisplayManager::GetInstance() {
- static OnScreenKeyboardDisplayManager* instance = nullptr;
- if (!instance) {
- instance = new OnScreenKeyboardDisplayManager;
- ANNOTATE_LEAKING_OBJECT_PTR(instance);
- }
- return instance;
-}
-
-bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard(
- OnScreenKeyboardObserver* observer) {
- if (base::win::GetVersion() < base::win::VERSION_WIN8)
- return false;
-
- if (base::win::IsKeyboardPresentOnSlate(nullptr, ui::GetHiddenWindow()))
- return false;
-
- if (osk_path_.empty() && !GetOSKPath(&osk_path_)) {
- DLOG(WARNING) << "Failed to get on screen keyboard path from registry";
- return false;
- }
-
- HINSTANCE ret = ::ShellExecuteW(nullptr, L"", osk_path_.c_str(), nullptr,
- nullptr, SW_SHOW);
-
- bool success = reinterpret_cast<intptr_t>(ret) > 32;
- if (success) {
- // If multiple calls to DisplayVirtualKeyboard occur one after the other,
- // the last observer would be the one to get notifications.
- keyboard_detector_.reset(new OnScreenKeyboardDetector);
- if (observer)
- keyboard_detector_->AddObserver(observer);
- keyboard_detector_->DetectKeyboard(::GetForegroundWindow());
- }
- return success;
-}
-
-bool OnScreenKeyboardDisplayManager::DismissVirtualKeyboard() {
- if (base::win::GetVersion() < base::win::VERSION_WIN8)
- return false;
-
- return keyboard_detector_ ? keyboard_detector_->DismissKeyboard() : false;
-}
-
-void OnScreenKeyboardDisplayManager::RemoveObserver(
- OnScreenKeyboardObserver* observer) {
- if (keyboard_detector_)
- keyboard_detector_->RemoveObserver(observer);
-}
-
-bool OnScreenKeyboardDisplayManager::GetOSKPath(base::string16* osk_path) {
- DCHECK(osk_path);
-
- // We need to launch TabTip.exe from the location specified under the
- // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}}
- // CLSID.
- // TabTip.exe is typically found at
- // c:\program files\common files\microsoft shared\ink on English Windows.
- // We don't want to launch TabTip.exe from
- // c:\program files (x86)\common files\microsoft shared\ink. This path is
- // normally found on 64 bit Windows.
- base::win::RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath,
- KEY_READ | KEY_WOW64_64KEY);
- DWORD osk_path_length = 1024;
- if (key.ReadValue(nullptr, base::WriteInto(osk_path, osk_path_length),
- &osk_path_length, nullptr) != ERROR_SUCCESS) {
- return false;
- }
-
- osk_path->resize(base::string16::traits_type::length(osk_path->c_str()));
-
- *osk_path = base::ToLowerASCII(*osk_path);
-
- size_t common_program_files_offset = osk_path->find(L"%commonprogramfiles%");
- // Typically the path to TabTip.exe read from the registry will start with
- // %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) {
- // Preserve the beginning quote in the path.
- osk_path->erase(common_program_files_offset,
- wcslen(L"%commonprogramfiles%"));
- // The path read from the registry contains the %CommonProgramFiles%
- // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath
- // function returns the common program files path with the X86 suffix for
- // the FOLDERID_ProgramFilesCommon value.
- // To get the correct path to TabTip.exe we first read the environment
- // variable CommonProgramW6432 which points to the desired common
- // files path. Failing that we fallback to the SHGetKnownFolderPath API.
-
- // We then replace the %CommonProgramFiles% value with the actual common
- // files path found in the process.
- base::string16 common_program_files_path;
- DWORD buffer_size =
- GetEnvironmentVariable(L"CommonProgramW6432", nullptr, 0);
- if (buffer_size) {
- GetEnvironmentVariable(
- L"CommonProgramW6432",
- base::WriteInto(&common_program_files_path, buffer_size),
- buffer_size);
- DCHECK(!common_program_files_path.empty());
- } else {
- base::win::ScopedCoMem<wchar_t> common_program_files;
- if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr,
- &common_program_files))) {
- return false;
- }
- common_program_files_path = common_program_files;
- }
- osk_path->insert(common_program_files_offset, common_program_files_path);
- }
- return !osk_path->empty();
-}
-
-bool OnScreenKeyboardDisplayManager::IsKeyboardVisible() const {
- return OnScreenKeyboardDetector::IsKeyboardVisible(nullptr);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc
index b5afdead174..e25487ec101 100644
--- a/chromium/ui/base/win/shell.cc
+++ b/chromium/ui/base/win/shell.cc
@@ -56,13 +56,6 @@ bool InvokeShellExecute(const base::string16 path,
} // namespace
-bool OpenAnyViaShell(const base::string16& full_path,
- const base::string16& directory,
- const base::string16& args,
- DWORD mask) {
- return InvokeShellExecute(full_path, directory, args, base::string16(), mask);
-}
-
bool OpenFileViaShell(const base::FilePath& full_path) {
// Invoke the default verb on the file with no arguments.
return InvokeShellExecute(full_path.value(), full_path.DirName().value(),
diff --git a/chromium/ui/base/win/shell.h b/chromium/ui/base/win/shell.h
index c47e5ce3f47..46b625c43c3 100644
--- a/chromium/ui/base/win/shell.h
+++ b/chromium/ui/base/win/shell.h
@@ -34,17 +34,6 @@ UI_BASE_EXPORT bool OpenFolderViaShell(const base::FilePath& full_path);
// Note: Must be called on a thread that allows blocking.
UI_BASE_EXPORT bool OpenFileViaShell(const base::FilePath& full_path);
-// Lower level function that allows opening of non-files like urls or GUIDs
-// don't use it if one of the above will do. |mask| is a valid combination
-// of SEE_MASK_XXX as stated in MSDN. If there is no default application
-// registered for the item, it behaves the same as OpenFileViaShell.
-//
-// Note: Must be called on a thread that allows blocking.
-UI_BASE_EXPORT bool OpenAnyViaShell(const base::string16& full_path,
- const base::string16& directory,
- const base::string16& args,
- DWORD mask);
-
// Disables the ability of the specified window to be pinned to the taskbar or
// the Start menu. This will remove "Pin this program to taskbar" from the
// taskbar menu of the specified window.
diff --git a/chromium/ui/base/win/window_event_target.h b/chromium/ui/base/win/window_event_target.h
index 3e9240ef97e..0d3e9d3b78e 100644
--- a/chromium/ui/base/win/window_event_target.h
+++ b/chromium/ui/base/win/window_event_target.h
@@ -89,6 +89,36 @@ class UI_BASE_EXPORT WindowEventTarget {
// Notification from the forwarder window that its parent changed.
virtual void HandleParentChanged() = 0;
+ // Apply the transform from Direct Manipulation API.
+
+ // Calls ApplyPinchZoomScale() for pinch-zoom gesture. scale is the scale
+ // factor.
+ virtual void ApplyPinchZoomScale(float scale) = 0;
+
+ // Pinch gesture phase. The sequencing expected of these events.
+ // The sequence of calls is ApplyPinchZoomBegin(), any number of calls to
+ // ApplyPinchZoomScale() and finally ApplyPinchZoomEnd().
+ virtual void ApplyPinchZoomBegin() = 0;
+ virtual void ApplyPinchZoomEnd() = 0;
+
+ // Calls ApplyPanGestureScroll() for pan gesture, scroll_x and scroll_y are
+ // pixel precison scroll offset.
+ virtual void ApplyPanGestureScroll(int scroll_x, int scroll_y) = 0;
+
+ // Calls ApplyPanGestureFling() for pan inertia gesture, scroll_x and scroll_y
+ // are pixel precison scroll offset.
+ virtual void ApplyPanGestureFling(int scroll_x, int scroll_y) = 0;
+
+ // Pan gesture phase. The sequencing expected of these events.
+ // The sequence of calls is ApplyPanGestureScrollBegin(), any number of calls
+ // to ApplyPanGestureScroll(), ApplyPanGestureScrollEnd(),
+ // ApplyPanGestureFlingBegin(), any number of calls to ApplyPanGestureFling(),
+ // and finally ApplyPanGestureFlingEnd().
+ virtual void ApplyPanGestureScrollBegin(int scroll_x, int scroll_y) = 0;
+ virtual void ApplyPanGestureScrollEnd() = 0;
+ virtual void ApplyPanGestureFlingBegin() = 0;
+ virtual void ApplyPanGestureFlingEnd() = 0;
+
protected:
WindowEventTarget();
virtual ~WindowEventTarget();
diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc
index cefa609ca64..17b750b6e9f 100644
--- a/chromium/ui/base/x/selection_owner.cc
+++ b/chromium/ui/base/x/selection_owner.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_window_event_manager.h"
#include "ui/events/platform/x11/x11_event_source.h"
diff --git a/chromium/ui/base/x/selection_requestor.h b/chromium/ui/base/x/selection_requestor.h
index 65d944a121c..746a535669d 100644
--- a/chromium/ui/base/x/selection_requestor.h
+++ b/chromium/ui/base/x/selection_requestor.h
@@ -10,12 +10,12 @@
#include <vector>
#include "base/callback.h"
-#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/base/ui_base_export.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/x/x11_types.h"
namespace ui {
diff --git a/chromium/ui/base/x/selection_requestor_unittest.cc b/chromium/ui/base/x/selection_requestor_unittest.cc
index faac9a1c419..7cf997ec43d 100644
--- a/chromium/ui/base/x/selection_requestor_unittest.cc
+++ b/chromium/ui/base/x/selection_requestor_unittest.cc
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
@@ -67,8 +68,8 @@ class SelectionRequestorTest : public testing::Test {
0,
NULL);
- event_source_ = ui::PlatformEventSource::CreateDefault();
- CHECK(ui::PlatformEventSource::GetInstance());
+ event_source_ = PlatformEventSource::CreateDefault();
+ CHECK(PlatformEventSource::GetInstance());
requestor_.reset(new SelectionRequestor(x_display_, x_window_, NULL));
}
@@ -84,7 +85,7 @@ class SelectionRequestorTest : public testing::Test {
// |requestor_|'s window.
XID x_window_;
- std::unique_ptr<ui::PlatformEventSource> event_source_;
+ std::unique_ptr<PlatformEventSource> event_source_;
std::unique_ptr<SelectionRequestor> requestor_;
base::MessageLoopForUI message_loop_;
@@ -123,16 +124,15 @@ TEST_F(SelectionRequestorTest, NestedRequests) {
XAtom target1 = gfx::GetAtom("TARGET1");
XAtom target2 = gfx::GetAtom("TARGET2");
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&PerformBlockingConvertSelection,
base::Unretained(requestor_.get()), selection,
target2, "Data2"));
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&SelectionRequestorTest::SendSelectionNotify,
base::Unretained(this), selection, target1, "Data1"));
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&SelectionRequestorTest::SendSelectionNotify,
base::Unretained(this), selection, target2, "Data2"));
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index 704ba93c06b..5be8a01f335 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -73,7 +73,7 @@ constexpr int kNetWMStateRemove = 0;
int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
if (base::MessageLoop::current()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&LogErrorEventDescription, d, *e));
+ FROM_HERE, base::BindOnce(&LogErrorEventDescription, d, *e));
} else {
LOG(ERROR)
<< "X error received: "
diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h
index a769101b0c8..e7942b98090 100644
--- a/chromium/ui/base/x/x11_util.h
+++ b/chromium/ui/base/x/x11_util.h
@@ -17,12 +17,12 @@
#include <vector>
#include "base/containers/flat_set.h"
-#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "ui/base/x/ui_base_x_export.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/x/x11_types.h"
typedef unsigned long XSharedMemoryId; // ShmSeg in the X headers.
diff --git a/chromium/ui/chromeos/BUILD.gn b/chromium/ui/chromeos/BUILD.gn
index c15c784e377..913671f1bf8 100644
--- a/chromium/ui/chromeos/BUILD.gn
+++ b/chromium/ui/chromeos/BUILD.gn
@@ -69,7 +69,7 @@ test("ui_chromeos_unittests") {
":chromeos",
"//base/test:test_support",
"//chromeos",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/aura:test_support",
diff --git a/chromium/ui/compositor/BUILD.gn b/chromium/ui/compositor/BUILD.gn
index 12788fef517..1e9a4724032 100644
--- a/chromium/ui/compositor/BUILD.gn
+++ b/chromium/ui/compositor/BUILD.gn
@@ -208,7 +208,7 @@ test("compositor_unittests") {
"//components/viz/common",
"//components/viz/service",
"//components/viz/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/ui/compositor/OWNERS b/chromium/ui/compositor/OWNERS
index 8bfe0cdad55..37217a38629 100644
--- a/chromium/ui/compositor/OWNERS
+++ b/chromium/ui/compositor/OWNERS
@@ -1,5 +1,7 @@
danakj@chromium.org
+flackr@chromium.org
piman@chromium.org
+smcgruer@chromium.org
vollick@chromium.org
# Animation
diff --git a/chromium/ui/compositor/callback_layer_animation_observer_unittest.cc b/chromium/ui/compositor/callback_layer_animation_observer_unittest.cc
index 6ea60b7fd37..eff7ee4de18 100644
--- a/chromium/ui/compositor/callback_layer_animation_observer_unittest.cc
+++ b/chromium/ui/compositor/callback_layer_animation_observer_unittest.cc
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/test/layer_animation_observer_test_api.h"
diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc
index c843ef6c644..ce16a0a14ee 100644
--- a/chromium/ui/compositor/compositor.cc
+++ b/chromium/ui/compositor/compositor.cc
@@ -336,9 +336,15 @@ void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
}
void Compositor::DisableSwapUntilResize() {
+ DCHECK(context_factory_private_);
context_factory_private_->ResizeDisplay(this, gfx::Size());
}
+void Compositor::ReenableSwap() {
+ DCHECK(context_factory_private_);
+ context_factory_private_->ResizeDisplay(this, size_);
+}
+
void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
std::unique_ptr<cc::SwapPromise> swap_promise(
new cc::LatencyInfoSwapPromise(latency_info));
diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h
index 78b36146063..a6a0cb9df02 100644
--- a/chromium/ui/compositor/compositor.h
+++ b/chromium/ui/compositor/compositor.h
@@ -260,6 +260,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
// Finishes all outstanding rendering and disables swapping on this surface
// until it is resized.
void DisableSwapUntilResize();
+ void ReenableSwap();
void SetLatencyInfo(const LatencyInfo& latency_info);
diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc
index ffd6f93c307..19a12d26e15 100644
--- a/chromium/ui/compositor/layer.cc
+++ b/chromium/ui/compositor/layer.cc
@@ -113,7 +113,8 @@ Layer::Layer()
device_scale_factor_(1.0f),
cache_render_surface_requests_(0),
deferred_paint_requests_(0),
- trilinear_filtering_request_(0) {
+ trilinear_filtering_request_(0),
+ weak_ptr_factory_(this) {
CreateCcLayer();
}
@@ -140,7 +141,8 @@ Layer::Layer(LayerType type)
device_scale_factor_(1.0f),
cache_render_surface_requests_(0),
deferred_paint_requests_(0),
- trilinear_filtering_request_(0) {
+ trilinear_filtering_request_(0),
+ weak_ptr_factory_(this) {
CreateCcLayer();
}
@@ -193,7 +195,8 @@ std::unique_ptr<Layer> Layer::Clone() const {
surface_layer_->deadline_in_frames()
? cc::DeadlinePolicy::UseSpecifiedDeadline(
*surface_layer_->deadline_in_frames())
- : cc::DeadlinePolicy::UseDefaultDeadline());
+ : cc::DeadlinePolicy::UseDefaultDeadline(),
+ surface_layer_->stretch_content_to_fill_bounds());
}
if (surface_layer_->fallback_surface_id().is_valid())
clone->SetFallbackSurfaceId(surface_layer_->fallback_surface_id());
@@ -627,7 +630,7 @@ void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
DCHECK(child->cc_layer_);
cc_layer_->AddChild(child->cc_layer_);
}
- cc_layer_->SetLayerClient(this);
+ cc_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
cc_layer_->SetTransformOrigin(gfx::Point3F());
cc_layer_->SetContentsOpaque(fills_bounds_opaquely_);
cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN);
@@ -706,6 +709,11 @@ void Layer::RemoveTrilinearFilteringRequest() {
cc_layer_->SetTrilinearFiltering(false);
}
+bool Layer::StretchContentToFillBounds() const {
+ DCHECK(surface_layer_);
+ return surface_layer_->stretch_content_to_fill_bounds();
+}
+
void Layer::SetTransferableResource(
const viz::TransferableResource& resource,
std::unique_ptr<viz::SingleReleaseCallback> release_callback,
@@ -713,6 +721,7 @@ void Layer::SetTransferableResource(
DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
DCHECK(!resource.mailbox_holder.mailbox.IsZero());
DCHECK(release_callback);
+ DCHECK(!resource.is_software);
if (!texture_layer_.get()) {
scoped_refptr<cc::TextureLayer> new_layer =
cc::TextureLayer::CreateForMailbox(this);
@@ -752,25 +761,28 @@ bool Layer::TextureFlipped() const {
void Layer::SetShowPrimarySurface(const viz::SurfaceId& surface_id,
const gfx::Size& frame_size_in_dip,
SkColor default_background_color,
- const cc::DeadlinePolicy& deadline_policy) {
+ const cc::DeadlinePolicy& deadline_policy,
+ bool stretch_content_to_fill_bounds) {
DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
if (!surface_layer_) {
scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create();
+ new_layer->SetHitTestable(true);
SwitchToLayer(new_layer);
surface_layer_ = new_layer;
}
surface_layer_->SetPrimarySurfaceId(surface_id, deadline_policy);
surface_layer_->SetBackgroundColor(default_background_color);
+ surface_layer_->SetStretchContentToFillBounds(stretch_content_to_fill_bounds);
frame_size_in_dip_ = frame_size_in_dip;
RecomputeDrawsContentAndUVRect();
for (const auto& mirror : mirrors_) {
- mirror->dest()->SetShowPrimarySurface(surface_id, frame_size_in_dip,
- default_background_color,
- deadline_policy);
+ mirror->dest()->SetShowPrimarySurface(
+ surface_id, frame_size_in_dip, default_background_color,
+ deadline_policy, stretch_content_to_fill_bounds);
}
}
@@ -1015,6 +1027,7 @@ size_t Layer::GetApproximateUnsharedMemoryUsage() const {
}
bool Layer::PrepareTransferableResource(
+ cc::SharedBitmapIdRegistrar* bitmap_registar,
viz::TransferableResource* resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) {
if (!transfer_release_callback_)
@@ -1046,7 +1059,7 @@ Layer::TakeDebugInfo(cc::Layer* layer) {
}
void Layer::didUpdateMainThreadScrollingReasons() {}
-void Layer::didChangeScrollbarsHidden(bool) {}
+void Layer::didChangeScrollbarsHiddenIfOverlay(bool) {}
void Layer::CollectAnimators(
std::vector<scoped_refptr<LayerAnimator>>* animators) {
@@ -1132,9 +1145,10 @@ void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds,
void Layer::SetTransformFromAnimation(const gfx::Transform& transform,
PropertyChangeReason reason) {
+ const gfx::Transform old_transform = this->transform();
cc_layer_->SetTransform(transform);
if (delegate_)
- delegate_->OnLayerTransformed(reason);
+ delegate_->OnLayerTransformed(old_transform, reason);
}
void Layer::SetOpacityFromAnimation(float opacity,
@@ -1254,7 +1268,7 @@ void Layer::CreateCcLayer() {
cc_layer_->SetTransformOrigin(gfx::Point3F());
cc_layer_->SetContentsOpaque(true);
cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN);
- cc_layer_->SetLayerClient(this);
+ cc_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
cc_layer_->SetElementId(cc::ElementId(cc_layer_->id()));
RecomputePosition();
}
diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h
index 8200c6d43be..736bd3c2bec 100644
--- a/chromium/ui/compositor/layer.h
+++ b/chromium/ui/compositor/layer.h
@@ -14,6 +14,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
#include "cc/base/region.h"
@@ -292,8 +293,8 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
const std::string& name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
- // Set new TransferableResource for this layer. Note that |resource| may hold
- // a handle for a shared memory resource or a gpu texture.
+ // Set new TransferableResource for this layer. This method only supports
+ // a gpu-backed |resource|.
void SetTransferableResource(
const viz::TransferableResource& resource,
std::unique_ptr<viz::SingleReleaseCallback> release_callback,
@@ -307,7 +308,8 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
void SetShowPrimarySurface(const viz::SurfaceId& surface_id,
const gfx::Size& frame_size_in_dip,
SkColor default_background_color,
- const cc::DeadlinePolicy& deadline_policy);
+ const cc::DeadlinePolicy& deadline_policy,
+ bool stretch_content_to_fill_bounds);
// In the event that the primary surface is not yet available in the
// display compositor, the fallback surface will be used.
@@ -394,6 +396,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// TextureLayerClient implementation.
bool PrepareTransferableResource(
+ cc::SharedBitmapIdRegistrar* bitmap_registar,
viz::TransferableResource* resource,
std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override;
@@ -403,7 +406,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> TakeDebugInfo(
cc::Layer* layer) override;
void didUpdateMainThreadScrollingReasons() override;
- void didChangeScrollbarsHidden(bool) override;
+ void didChangeScrollbarsHiddenIfOverlay(bool) override;
// Triggers a call to SwitchToLayer.
void SwitchCCLayerForTest();
@@ -438,6 +441,10 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// while attached to the main layer before the main layer is deleted.
const Layer* layer_mask_back_link() const { return layer_mask_back_link_; }
+ // If |surface_layer_| exists, return whether the contents should stretch to
+ // fill the bounds of |this|. Defaults to false.
+ bool StretchContentToFillBounds() const;
+
private:
friend class LayerOwner;
class LayerMirror;
@@ -618,6 +625,8 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// layer.
unsigned trilinear_filtering_request_;
+ base::WeakPtrFactory<Layer> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/chromium/ui/compositor/layer_animation_element.cc b/chromium/ui/compositor/layer_animation_element.cc
index 38bd26b8a60..3d965dd000c 100644
--- a/chromium/ui/compositor/layer_animation_element.cc
+++ b/chromium/ui/compositor/layer_animation_element.cc
@@ -8,7 +8,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/keyframe_model.h"
diff --git a/chromium/ui/compositor/layer_animator_unittest.cc b/chromium/ui/compositor/layer_animator_unittest.cc
index 6dc9a0cadf0..389cedcbfdc 100644
--- a/chromium/ui/compositor/layer_animator_unittest.cc
+++ b/chromium/ui/compositor/layer_animator_unittest.cc
@@ -10,7 +10,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/compositor/layer_delegate.cc b/chromium/ui/compositor/layer_delegate.cc
index d2f8da54fe8..153c7f5c47e 100644
--- a/chromium/ui/compositor/layer_delegate.cc
+++ b/chromium/ui/compositor/layer_delegate.cc
@@ -9,7 +9,8 @@ namespace ui {
void LayerDelegate::OnLayerBoundsChanged(const gfx::Rect& old_bounds,
PropertyChangeReason reason) {}
-void LayerDelegate::OnLayerTransformed(PropertyChangeReason reason) {}
+void LayerDelegate::OnLayerTransformed(const gfx::Transform& old_transform,
+ PropertyChangeReason reason) {}
void LayerDelegate::OnLayerOpacityChanged(PropertyChangeReason reason) {}
diff --git a/chromium/ui/compositor/layer_delegate.h b/chromium/ui/compositor/layer_delegate.h
index eb8dc714362..1b3c40b4804 100644
--- a/chromium/ui/compositor/layer_delegate.h
+++ b/chromium/ui/compositor/layer_delegate.h
@@ -10,6 +10,7 @@
namespace gfx {
class Rect;
+class Transform;
}
namespace ui {
@@ -35,7 +36,8 @@ class COMPOSITOR_EXPORT LayerDelegate {
// the property was set directly or by an animation. This will be called
// before the first frame of an animation is rendered and when the animation
// ends, but not necessarily at every frame of the animation.
- virtual void OnLayerTransformed(PropertyChangeReason reason);
+ virtual void OnLayerTransformed(const gfx::Transform& old_transform,
+ PropertyChangeReason reason);
virtual void OnLayerOpacityChanged(PropertyChangeReason reason);
protected:
diff --git a/chromium/ui/compositor/layer_owner.cc b/chromium/ui/compositor/layer_owner.cc
index 2806e81b6b0..ed68ad2b989 100644
--- a/chromium/ui/compositor/layer_owner.cc
+++ b/chromium/ui/compositor/layer_owner.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
namespace ui {
diff --git a/chromium/ui/compositor/layer_owner_unittest.cc b/chromium/ui/compositor/layer_owner_unittest.cc
index 3a6b60b7083..2e6fb209019 100644
--- a/chromium/ui/compositor/layer_owner_unittest.cc
+++ b/chromium/ui/compositor/layer_owner_unittest.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/test/null_task_runner.h"
#include "cc/animation/single_keyframe_effect_animation.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index a544b33d938..c56eee9bbfc 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -15,7 +15,6 @@
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
@@ -33,6 +32,7 @@
#include "components/viz/common/frame_sinks/copy_output_request.h"
#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/surface_id.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -314,7 +314,8 @@ class TestLayerDelegate : public LayerDelegate {
MOCK_METHOD2(OnLayerBoundsChanged,
void(const gfx::Rect&, PropertyChangeReason));
- MOCK_METHOD1(OnLayerTransformed, void(PropertyChangeReason));
+ MOCK_METHOD2(OnLayerTransformed,
+ void(const gfx::Transform&, PropertyChangeReason));
MOCK_METHOD1(OnLayerOpacityChanged, void(PropertyChangeReason));
void reset() {
@@ -571,10 +572,11 @@ TEST(LayerStandaloneTest, ReleaseMailboxOnDestruction) {
bool callback_run = false;
auto resource = viz::TransferableResource::MakeGL(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
- layer->SetTransferableResource(resource,
- viz::SingleReleaseCallback::Create(
- base::Bind(ReturnMailbox, &callback_run)),
- gfx::Size(10, 10));
+ layer->SetTransferableResource(
+ resource,
+ viz::SingleReleaseCallback::Create(
+ base::BindOnce(ReturnMailbox, &callback_run)),
+ gfx::Size(10, 10));
EXPECT_FALSE(callback_run);
layer.reset();
EXPECT_TRUE(callback_run);
@@ -891,6 +893,48 @@ TEST_F(LayerWithDelegateTest, Mirroring) {
EXPECT_EQ(new_bounds, mirror->bounds());
}
+// Tests for SurfaceLayer cloning and mirroring. This tests certain properties
+// are preserved.
+TEST_F(LayerWithDelegateTest, SurfaceLayerCloneAndMirror) {
+ const viz::FrameSinkId arbitrary_frame_sink(1, 1);
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR));
+
+ viz::LocalSurfaceId local_surface_id = allocator.GenerateId();
+ viz::SurfaceId surface_id_one(arbitrary_frame_sink, local_surface_id);
+ layer->SetShowPrimarySurface(surface_id_one, gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ EXPECT_FALSE(layer->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(layer->cc_layer_for_testing())
+ ->hit_testable());
+
+ auto clone = layer->Clone();
+ EXPECT_FALSE(clone->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(clone->cc_layer_for_testing())
+ ->hit_testable());
+ auto mirror = layer->Mirror();
+ EXPECT_FALSE(mirror->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(mirror->cc_layer_for_testing())
+ ->hit_testable());
+
+ local_surface_id = allocator.GenerateId();
+ viz::SurfaceId surface_id_two(arbitrary_frame_sink, local_surface_id);
+ layer->SetShowPrimarySurface(surface_id_two, gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), true);
+ EXPECT_TRUE(layer->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(layer->cc_layer_for_testing())
+ ->hit_testable());
+
+ clone = layer->Clone();
+ EXPECT_TRUE(clone->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(clone->cc_layer_for_testing())
+ ->hit_testable());
+ mirror = layer->Mirror();
+ EXPECT_TRUE(mirror->StretchContentToFillBounds());
+ EXPECT_TRUE(static_cast<cc::SurfaceLayer*>(mirror->cc_layer_for_testing())
+ ->hit_testable());
+}
+
class LayerWithNullDelegateTest : public LayerWithDelegateTest {
public:
LayerWithNullDelegateTest() {}
@@ -973,8 +1017,8 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
auto resource = viz::TransferableResource::MakeGL(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
l1->SetTransferableResource(resource,
- viz::SingleReleaseCallback::Create(
- base::Bind(ReturnMailbox, &callback1_run)),
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ ReturnMailbox, &callback1_run)),
gfx::Size(10, 10));
EXPECT_NE(before_layer, l1->cc_layer_for_testing());
@@ -990,8 +1034,8 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
resource = viz::TransferableResource::MakeGL(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
l1->SetTransferableResource(resource,
- viz::SingleReleaseCallback::Create(
- base::Bind(ReturnMailbox, &callback2_run)),
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ ReturnMailbox, &callback2_run)),
gfx::Size(10, 10));
EXPECT_TRUE(callback1_run);
EXPECT_FALSE(callback2_run);
@@ -1012,8 +1056,8 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
resource = viz::TransferableResource::MakeGL(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
l1->SetTransferableResource(resource,
- viz::SingleReleaseCallback::Create(
- base::Bind(ReturnMailbox, &callback3_run)),
+ viz::SingleReleaseCallback::Create(base::BindOnce(
+ ReturnMailbox, &callback3_run)),
gfx::Size(10, 10));
EXPECT_NE(before_layer, l1->cc_layer_for_testing());
@@ -1159,10 +1203,10 @@ TEST_F(LayerWithNullDelegateTest, SetBoundsSchedulesPaint) {
// Checks that the damage rect for a TextureLayer is empty after a commit.
TEST_F(LayerWithNullDelegateTest, EmptyDamagedRect) {
base::RunLoop run_loop;
- viz::ReleaseCallback callback =
- base::Bind([](base::RunLoop* run_loop, const gpu::SyncToken& sync_token,
- bool is_lost) { run_loop->Quit(); },
- base::Unretained(&run_loop));
+ viz::ReleaseCallback callback = base::BindOnce(
+ [](base::RunLoop* run_loop, const gpu::SyncToken& sync_token,
+ bool is_lost) { run_loop->Quit(); },
+ base::Unretained(&run_loop));
std::unique_ptr<Layer> root(CreateLayer(LAYER_SOLID_COLOR));
auto resource = viz::TransferableResource::MakeGL(
@@ -1851,23 +1895,17 @@ TEST_F(LayerWithDelegateTest, ExternalContent) {
before = child->cc_layer_for_testing();
child->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
scoped_refptr<cc::Layer> after = child->cc_layer_for_testing();
const auto* surface = static_cast<cc::SurfaceLayer*>(after.get());
EXPECT_TRUE(after.get());
EXPECT_NE(before.get(), after.get());
EXPECT_EQ(base::nullopt, surface->deadline_in_frames());
- child->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
- SK_ColorWHITE,
- cc::DeadlinePolicy::UseSpecifiedDeadline(4u));
+ child->SetShowPrimarySurface(
+ viz::SurfaceId(), gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseSpecifiedDeadline(4u), false);
EXPECT_EQ(4u, surface->deadline_in_frames());
-
- // Changing to painted content should change the underlying cc layer.
- before = child->cc_layer_for_testing();
- child->SetShowSolidColorContent();
- EXPECT_TRUE(child->cc_layer_for_testing());
- EXPECT_NE(before.get(), child->cc_layer_for_testing());
}
TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
@@ -1877,7 +1915,7 @@ TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
viz::FrameSinkId(0, 1),
viz::LocalSurfaceId(2, base::UnguessableToken::Create()));
layer->SetShowPrimarySurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
const auto mirror = layer->Mirror();
auto* const cc_layer = mirror->cc_layer_for_testing();
@@ -1890,12 +1928,12 @@ TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
viz::SurfaceId(viz::FrameSinkId(1, 2),
viz::LocalSurfaceId(3, base::UnguessableToken::Create()));
layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
// The mirror should continue to use the same cc_layer.
EXPECT_EQ(cc_layer, mirror->cc_layer_for_testing());
layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
// Surface updates propagate to the mirror.
EXPECT_EQ(surface_id, surface->primary_surface_id());
@@ -1917,7 +1955,7 @@ TEST_F(LayerWithDelegateTest, LayerFiltersSurvival) {
scoped_refptr<cc::Layer> before = layer->cc_layer_for_testing();
layer->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline());
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
EXPECT_EQ(layer->layer_grayscale(), 0.5f);
EXPECT_TRUE(layer->cc_layer_for_testing());
EXPECT_NE(before.get(), layer->cc_layer_for_testing());
@@ -2374,16 +2412,32 @@ TEST(LayerDelegateTest, OnLayerTransformed) {
auto layer = std::make_unique<Layer>(LAYER_TEXTURED);
testing::StrictMock<TestLayerDelegate> delegate;
layer->set_delegate(&delegate);
- gfx::Transform target_transform;
- target_transform.Skew(10.0f, 5.0f);
+ gfx::Transform target_transform1;
+ target_transform1.Skew(10.0f, 5.0f);
+ {
+ EXPECT_CALL(delegate,
+ OnLayerTransformed(gfx::Transform(),
+ PropertyChangeReason::NOT_FROM_ANIMATION))
+ .WillOnce(testing::Invoke(
+ [&](const gfx::Transform& old_transform, PropertyChangeReason) {
+ // Verify that |layer->transform()| returns the correct value when
+ // the delegate is notified.
+ EXPECT_EQ(target_transform1, layer->transform());
+ }));
+ layer->SetTransform(target_transform1);
+ }
+ gfx::Transform target_transform2;
+ target_transform2.Skew(10.0f, 5.0f);
EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::NOT_FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
- // Verify that |layer->transform()| returns the correct value when the
- // delegate is notified.
- EXPECT_EQ(layer->transform(), target_transform);
- }));
- layer->SetTransform(target_transform);
+ OnLayerTransformed(target_transform1,
+ PropertyChangeReason::NOT_FROM_ANIMATION))
+ .WillOnce(testing::Invoke(
+ [&](const gfx::Transform& old_transform, PropertyChangeReason) {
+ // Verify that |layer->transform()| returns the correct value when
+ // the delegate is notified.
+ EXPECT_EQ(target_transform2, layer->transform());
+ }));
+ layer->SetTransform(target_transform2);
}
// Verify that LayerDelegate::OnLayerTransformed() is called at every step of a
@@ -2417,8 +2471,10 @@ TEST(LayerDelegateTest, OnLayerTransformedNonThreadedAnimation) {
ASSERT_FALSE(element->IsThreaded(layer.get()));
LayerAnimationElement* element_raw = element.get();
EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
+ OnLayerTransformed(gfx::Transform(),
+ PropertyChangeReason::FROM_ANIMATION))
+ .WillOnce(testing::Invoke([&](const gfx::Transform& old_transform,
+ PropertyChangeReason) {
// Verify that |layer->transform()| returns the correct value when the
// delegate is notified.
EXPECT_EQ(layer->transform(), initial_transform);
@@ -2430,19 +2486,23 @@ TEST(LayerDelegateTest, OnLayerTransformedNonThreadedAnimation) {
// Progress the animation.
EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
- // Verify that |layer->transform()| returns the correct value when the
- // delegate is notified.
- EXPECT_EQ(layer->transform(), step_transform);
- }));
+ OnLayerTransformed(initial_transform,
+ PropertyChangeReason::FROM_ANIMATION))
+ .WillOnce(testing::Invoke(
+ [&](const gfx::Transform& old_transform, PropertyChangeReason) {
+ // Verify that |layer->transform()| returns the correct value when
+ // the delegate is notified.
+ EXPECT_EQ(layer->transform(), step_transform);
+ }));
test_controller.Step(element_raw->duration() / 2);
testing::Mock::VerifyAndClear(&delegate);
// End the animation.
- EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
+ EXPECT_CALL(
+ delegate,
+ OnLayerTransformed(step_transform, PropertyChangeReason::FROM_ANIMATION))
+ .WillOnce(testing::Invoke([&](const gfx::Transform& old_transform,
+ PropertyChangeReason) {
// Verify that |layer->transform()| returns the correct value when the
// delegate is notified.
EXPECT_EQ(layer->transform(), target_transform);
@@ -2477,8 +2537,10 @@ TEST(LayerDelegateTest, OnLayerTransformedThreadedAnimation) {
ASSERT_TRUE(element->IsThreaded(layer.get()));
LayerAnimationElement* element_raw = element.get();
EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
+ OnLayerTransformed(gfx::Transform(),
+ PropertyChangeReason::FROM_ANIMATION))
+ .WillOnce(testing::Invoke([&](const gfx::Transform& old_transform,
+ PropertyChangeReason) {
// Verify that |layer->transform()| returns the correct value when the
// delegate is notified.
EXPECT_EQ(layer->transform(), initial_transform);
@@ -2491,8 +2553,10 @@ TEST(LayerDelegateTest, OnLayerTransformedThreadedAnimation) {
// End the animation.
EXPECT_CALL(delegate,
- OnLayerTransformed(PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](PropertyChangeReason) {
+ OnLayerTransformed(initial_transform,
+ PropertyChangeReason::FROM_ANIMATION))
+ .WillOnce(testing::Invoke([&](const gfx::Transform& old_transform,
+ PropertyChangeReason) {
// Verify that |layer->transform()| returns the correct value when the
// delegate is notified.
EXPECT_EQ(layer->transform(), target_transform);
diff --git a/chromium/ui/compositor/run_all_unittests.cc b/chromium/ui/compositor/run_all_unittests.cc
index e2f22adc452..40b96f9542d 100644
--- a/chromium/ui/compositor/run_all_unittests.cc
+++ b/chromium/ui/compositor/run_all_unittests.cc
@@ -13,6 +13,7 @@ int main(int argc, char** argv) {
mojo::edk::Init();
return base::LaunchUnitTests(
- argc, argv, base::Bind(&ui::test::CompositorTestSuite::Run,
- base::Unretained(&test_suite)));
+ argc, argv,
+ base::BindOnce(&ui::test::CompositorTestSuite::Run,
+ base::Unretained(&test_suite)));
}
diff --git a/chromium/ui/compositor_extra/BUILD.gn b/chromium/ui/compositor_extra/BUILD.gn
new file mode 100644
index 00000000000..ef59ba4b804
--- /dev/null
+++ b/chromium/ui/compositor_extra/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("compositor_extra") {
+ sources = [
+ "shadow.cc",
+ "shadow.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/base",
+ "//ui/compositor",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
diff --git a/chromium/ui/compositor_extra/DEPS b/chromium/ui/compositor_extra/DEPS
new file mode 100644
index 00000000000..ed9f0a5c635
--- /dev/null
+++ b/chromium/ui/compositor_extra/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+ui/base",
+ "+ui/compositor",
+ "+ui/gfx",
+]
diff --git a/chromium/ui/wm/core/shadow.cc b/chromium/ui/compositor_extra/shadow.cc
index 20def6b8976..d14b7e35f15 100644
--- a/chromium/ui/wm/core/shadow.cc
+++ b/chromium/ui/compositor_extra/shadow.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/wm/core/shadow.h"
+#include "ui/compositor_extra/shadow.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/layer.h"
@@ -10,7 +10,7 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/shadow_util.h"
-namespace wm {
+namespace ui {
namespace {
@@ -173,4 +173,4 @@ void Shadow::UpdateLayerBounds() {
blur_region.height()));
}
-} // namespace wm
+} // namespace ui
diff --git a/chromium/ui/wm/core/shadow.h b/chromium/ui/compositor_extra/shadow.h
index 4c224a20b45..fb47899953c 100644
--- a/chromium/ui/wm/core/shadow.h
+++ b/chromium/ui/compositor_extra/shadow.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_WM_CORE_SHADOW_H_
-#define UI_WM_CORE_SHADOW_H_
+#ifndef UI_COMPOSITOR_EXTRA_SHADOW_H_
+#define UI_COMPOSITOR_EXTRA_SHADOW_H_
#include <memory>
#include "base/macros.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/wm/core/wm_core_export.h"
namespace gfx {
struct ShadowDetails;
@@ -18,12 +17,9 @@ struct ShadowDetails;
namespace ui {
class Layer;
-} // namespace ui
-
-namespace wm {
// Simple class that draws a drop shadow around content at given bounds.
-class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver {
+class Shadow : public ui::ImplicitAnimationObserver {
public:
Shadow();
~Shadow() override;
@@ -103,6 +99,6 @@ class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver {
DISALLOW_COPY_AND_ASSIGN(Shadow);
};
-} // namespace wm
+} // namespace ui
-#endif // UI_WM_CORE_SHADOW_H_
+#endif // UI_COMPOSITOR_EXTRA_SHADOW_H_
diff --git a/chromium/ui/wm/core/shadow_unittest.cc b/chromium/ui/compositor_extra/shadow_unittest.cc
index 28cef9b62ac..10e6bfec525 100644
--- a/chromium/ui/wm/core/shadow_unittest.cc
+++ b/chromium/ui/compositor_extra/shadow_unittest.cc
@@ -2,14 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/wm/core/shadow.h"
+#include "ui/compositor_extra/shadow.h"
#include "base/macros.h"
-#include "ui/aura/test/aura_test_base.h"
+#include "base/test/test_discardable_memory_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/shadow_util.h"
#include "ui/gfx/shadow_value.h"
-namespace wm {
+namespace ui {
namespace {
constexpr int kElevationLarge = 24;
@@ -28,10 +32,30 @@ gfx::Size NineboxImageSizeForElevationAndCornerRadius(int elevation,
return bounds.size();
}
-using ShadowTest = aura::test::AuraTestBase;
+class ShadowTest : public testing::Test {
+ protected:
+ ShadowTest() {}
+ ~ShadowTest() override {}
+
+ void SetUp() override {
+ base::DiscardableMemoryAllocator::SetInstance(
+ &discardable_memory_allocator_);
+ }
+
+ void TearDown() override {
+ base::DiscardableMemoryAllocator::SetInstance(nullptr);
+ }
+
+ private:
+ base::TestDiscardableMemoryAllocator discardable_memory_allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShadowTest);
+};
// Test if the proper content bounds is calculated based on the current style.
TEST_F(ShadowTest, SetContentBounds) {
+ ScopedAnimationDurationScaleMode zero_duration_mode(
+ ScopedAnimationDurationScaleMode::ZERO_DURATION);
// Verify that layer bounds are outset from content bounds.
Shadow shadow;
{
@@ -103,4 +127,4 @@ TEST_F(ShadowTest, AdjustRoundedCornerRadius) {
}
} // namespace
-} // namespace wm
+} // namespace ui
diff --git a/chromium/ui/content_accelerators/BUILD.gn b/chromium/ui/content_accelerators/BUILD.gn
index d464721ac66..74e8747ac69 100644
--- a/chromium/ui/content_accelerators/BUILD.gn
+++ b/chromium/ui/content_accelerators/BUILD.gn
@@ -9,7 +9,7 @@ source_set("content_accelerators") {
]
deps = [
- "//third_party/WebKit/public:blink_headers",
+ "//third_party/blink/public:blink_headers",
"//ui/base",
"//ui/events",
"//ui/events/blink",
diff --git a/chromium/ui/content_accelerators/DEPS b/chromium/ui/content_accelerators/DEPS
index 9e6e70d07c3..be517913e71 100644
--- a/chromium/ui/content_accelerators/DEPS
+++ b/chromium/ui/content_accelerators/DEPS
@@ -2,5 +2,5 @@ include_rules = [
"+content/public",
"+ui/base",
"+ui/events",
- "+third_party/WebKit/public/platform/WebInputEvent.h",
+ "+third_party/blink/public/platform/web_input_event.h",
]
diff --git a/chromium/ui/content_accelerators/accelerator_util.cc b/chromium/ui/content_accelerators/accelerator_util.cc
index 6705f807b10..09c3be2f90c 100644
--- a/chromium/ui/content_accelerators/accelerator_util.cc
+++ b/chromium/ui/content_accelerators/accelerator_util.cc
@@ -5,7 +5,7 @@
#include "ui/content_accelerators/accelerator_util.h"
#include "build/build_config.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
diff --git a/chromium/ui/display/BUILD.gn b/chromium/ui/display/BUILD.gn
index 381e32449ff..c19111efec9 100644
--- a/chromium/ui/display/BUILD.gn
+++ b/chromium/ui/display/BUILD.gn
@@ -113,6 +113,8 @@ static_library("test_support") {
"test/display_matchers.cc",
"test/display_matchers.h",
"test/display_test_util.h",
+ "test/scoped_screen_override.cc",
+ "test/scoped_screen_override.h",
"test/test_screen.cc",
"test/test_screen.h",
"win/test/screen_util_win.cc",
@@ -146,6 +148,7 @@ test("display_unittests") {
"manager/chromeos/configure_displays_task_unittest.cc",
"manager/chromeos/display_change_observer_unittest.cc",
"manager/chromeos/display_configurator_unittest.cc",
+ "manager/chromeos/display_utils_unittest.cc",
"manager/chromeos/query_content_protection_task_unittest.cc",
"manager/chromeos/touch_device_manager_unittest.cc",
"manager/chromeos/touch_transform_controller_unittest.cc",
diff --git a/chromium/ui/display/OWNERS b/chromium/ui/display/OWNERS
index e60ce6577fc..0101ef32916 100644
--- a/chromium/ui/display/OWNERS
+++ b/chromium/ui/display/OWNERS
@@ -1,4 +1,7 @@
+afakhry@chromium.org
derat@chromium.org
+dnicoara@chromium.org
marcheu@chromium.org
oshima@chromium.org
-afakhry@chromium.org
+
+# COMPONENT: UI
diff --git a/chromium/ui/display/display.cc b/chromium/ui/display/display.cc
index 9a10474c49a..9aedc85745d 100644
--- a/chromium/ui/display/display.cc
+++ b/chromium/ui/display/display.cc
@@ -268,7 +268,7 @@ gfx::Size Display::GetSizeInPixel() const {
std::string Display::ToString() const {
return base::StringPrintf(
- "Display[%lld] bounds=%s, workarea=%s, scale=%g, %s",
+ "Display[%lld] bounds=[%s], workarea=[%s], scale=%g, %s.",
static_cast<long long int>(id_), bounds_.ToString().c_str(),
work_area_.ToString().c_str(), device_scale_factor_,
IsInternal() ? "internal" : "external");
diff --git a/chromium/ui/display/display.h b/chromium/ui/display/display.h
index 49f76438ef3..f900c7e016a 100644
--- a/chromium/ui/display/display.h
+++ b/chromium/ui/display/display.h
@@ -220,9 +220,7 @@ class DISPLAY_EXPORT Display final {
// True if this is a monochrome display (e.g, for accessiblity). Used by media
// query APIs.
bool is_monochrome() const { return is_monochrome_; }
- void set_is_monochrome(bool is_monochrome) {
- is_monochrome_ = is_monochrome;
- }
+ void set_is_monochrome(bool is_monochrome) { is_monochrome_ = is_monochrome; }
bool operator==(const Display& rhs) const;
bool operator!=(const Display& rhs) const { return !(*this == rhs); }
diff --git a/chromium/ui/display/display_layout.cc b/chromium/ui/display/display_layout.cc
index 814e25255f2..e681213346c 100644
--- a/chromium/ui/display/display_layout.cc
+++ b/chromium/ui/display/display_layout.cc
@@ -16,6 +16,8 @@
#include "base/values.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
namespace display {
namespace {
@@ -329,6 +331,23 @@ void DeIntersectDisplays(int64_t primary_id,
UpdatePlacementList(display_list, placement_list);
}
+// Checks if the given point is over the radius vector described by its end
+// point |vector|. The point is over a vector if it's on its positive (left)
+// side. The method sees a point on the same line as the vector as being over
+// the vector.
+bool IsPointOverRadiusVector(const gfx::Point& point,
+ const gfx::Point& vector) {
+ // |point| is left of |vector| if its radius vector's scalar product with a
+ // vector orthogonal (and facing the positive side) to |vector| is positive.
+ //
+ // An orthogonal vector of (a, b) is (b, -a), as the scalar product of these
+ // two is 0.
+ // So, (x, y) is over (a, b) if x * b + y * (-a) >= 0, which is equivalent to
+ // x * b >= y * a.
+ return static_cast<int64_t>(point.x()) * static_cast<int64_t>(vector.y()) >=
+ static_cast<int64_t>(point.y()) * static_cast<int64_t>(vector.x());
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -634,6 +653,97 @@ DisplayPlacement DisplayLayout::FindPlacementById(int64_t display_id) const {
: DisplayPlacement(*iter);
}
+// Creates a display::DisplayPlacement value for |rectangle| relative to the
+// |reference| rectangle.
+// The layout consists of two values:
+// - position: Whether the rectangle is positioned left, right, over or under
+// the reference.
+// - offset: The rectangle's offset from the reference origin along the axis
+// opposite the position direction (if the rectangle is left or right along
+// y-axis, otherwise along x-axis).
+// The rectangle's position is calculated by dividing the space in areas defined
+// by the |reference|'s diagonals and finding the area |rectangle|'s center
+// point belongs. If the |rectangle| in the calculated layout does not share a
+// part of the bounds with the |reference|, the |rectangle| position in set to
+// the more suitable neighboring position (e.g. if |rectangle| is completely
+// over the |reference| top bound, it will be set to TOP) and the layout is
+// recalculated with the new position. This is to handle the case where the
+// rectangle shares an edge with the reference, but it's center is not in the
+// same area as the reference's edge, e.g.
+//
+// +---------------------+
+// | |
+// | REFERENCE |
+// | |
+// | |
+// +---------------------+
+// +-------------------------------------------------+
+// | RECTANGLE x |
+// +-------------------------------------------------+
+//
+// The rectangle shares an egde with the reference's bottom edge, but it's
+// center point is in the left area.
+
+// static
+DisplayPlacement DisplayLayout::CreatePlacementForRectangles(
+ const gfx::Rect& reference,
+ const gfx::Rect& rectangle) {
+ // Translate coordinate system so origin is in the reference's top left point
+ // (so the reference's down-diagonal vector starts in the (0, 0)) and scale it
+ // up by two (to avoid division when calculating the rectangle's center
+ // point).
+ gfx::Point center(2 * (rectangle.x() - reference.x()) + rectangle.width(),
+ 2 * (rectangle.y() - reference.y()) + rectangle.height());
+ gfx::Point down_diag(2 * reference.width(), 2 * reference.height());
+
+ bool is_top_right = IsPointOverRadiusVector(center, down_diag);
+
+ // Translate the coordinate system again, so the bottom right point of the
+ // reference is origin (so the reference's up-diagonal starts at (0, 0)).
+ // Note that the coordinate system is scaled by 2.
+ center.Offset(0, -2 * reference.height());
+ // Choose the vector orientation so the points on the diagonal are considered
+ // to be left.
+ gfx::Point up_diag(-2 * reference.width(), 2 * reference.height());
+
+ bool is_bottom_right = IsPointOverRadiusVector(center, up_diag);
+
+ DisplayPlacement::Position position;
+ if (is_top_right) {
+ position =
+ is_bottom_right ? DisplayPlacement::RIGHT : DisplayPlacement::TOP;
+ } else {
+ position =
+ is_bottom_right ? DisplayPlacement::BOTTOM : DisplayPlacement::LEFT;
+ }
+
+ // If the rectangle with the calculated position would not have common side
+ // with the reference, try to position it so it shares another edge with the
+ // reference.
+ if (is_top_right == is_bottom_right) {
+ if (rectangle.y() > reference.bottom()) {
+ // The rectangle is left or right, but completely under the reference.
+ position = DisplayPlacement::BOTTOM;
+ } else if (rectangle.bottom() < reference.y()) {
+ // The rectangle is left or right, but completely over the reference.
+ position = DisplayPlacement::TOP;
+ }
+ } else {
+ if (rectangle.x() > reference.right()) {
+ // The rectangle is over or under, but completely right of the reference.
+ position = DisplayPlacement::RIGHT;
+ } else if (rectangle.right() < reference.x()) {
+ // The rectangle is over or under, but completely left of the reference.
+ position = DisplayPlacement::LEFT;
+ }
+ }
+ int offset = (position == DisplayPlacement::LEFT ||
+ position == DisplayPlacement::RIGHT)
+ ? rectangle.y()
+ : rectangle.x();
+ return DisplayPlacement(position, offset);
+}
+
// static
bool DisplayLayout::ApplyDisplayPlacement(const DisplayPlacement& placement,
Displays* display_list,
diff --git a/chromium/ui/display/display_layout.h b/chromium/ui/display/display_layout.h
index e269d589300..3f173780662 100644
--- a/chromium/ui/display/display_layout.h
+++ b/chromium/ui/display/display_layout.h
@@ -15,6 +15,10 @@
#include "base/strings/string_piece.h"
#include "ui/display/display_export.h"
+namespace gfx {
+class Rect;
+}
+
namespace display {
class Display;
@@ -123,6 +127,12 @@ class DISPLAY_EXPORT DisplayLayout final {
// otherwise returns a DisplayPlacement with an invalid display id.
DisplayPlacement FindPlacementById(int64_t display_id) const;
+ // Creates a display::DisplayPlacement value for |rectangle| relative to the
+ // |reference| rectangle.
+ static DisplayPlacement CreatePlacementForRectangles(
+ const gfx::Rect& reference,
+ const gfx::Rect& rectangle);
+
private:
// Apply the display placement to |display_list|.
// Returns true if the display bounds were updated.
diff --git a/chromium/ui/display/display_switches.cc b/chromium/ui/display/display_switches.cc
index d06ee064e1e..880fba64afe 100644
--- a/chromium/ui/display/display_switches.cc
+++ b/chromium/ui/display/display_switches.cc
@@ -65,10 +65,27 @@ const base::Feature kHighDynamicRange{"HighDynamicRange",
base::FEATURE_ENABLED_BY_DEFAULT};
#if defined(OS_CHROMEOS)
-// Enables using the monitor's provided color space information when rendering.
+// Enables using the monitor's provided color space information when
+// rendering.
// TODO(mcasas): remove this flag http://crbug.com/771345.
const base::Feature kUseMonitorColorSpace{"UseMonitorColorSpace",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // OS_CHROMEOS
+
+// Enables the slider in display settings to modify the display zoom/size.
+// TODO(malaykeshav): Remove this in M68 when the feature has been in stable for
+// atleast one milestone.
+constexpr base::Feature kEnableDisplayZoomSetting{
+ "EnableDisplayZoomSetting",
+#if defined(OS_CHROMEOS)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
#endif
+};
+
+bool IsDisplayZoomSettingEnabled() {
+ return base::FeatureList::IsEnabled(kEnableDisplayZoomSetting);
+}
} // namespace features
diff --git a/chromium/ui/display/display_switches.h b/chromium/ui/display/display_switches.h
index da146eb5359..f2377204810 100644
--- a/chromium/ui/display/display_switches.h
+++ b/chromium/ui/display/display_switches.h
@@ -38,6 +38,11 @@ DISPLAY_EXPORT extern const base::Feature kHighDynamicRange;
DISPLAY_EXPORT extern const base::Feature kUseMonitorColorSpace;
#endif
+DISPLAY_EXPORT extern const base::Feature kEnableDisplayZoomSetting;
+
+// Returns true if experimental display zoom setting is enabled.
+DISPLAY_EXPORT bool IsDisplayZoomSettingEnabled();
+
} // namespace features
#endif // UI_DISPLAY_DISPLAY_SWITCHES_H_
diff --git a/chromium/ui/display/mac/screen_mac.mm b/chromium/ui/display/mac/screen_mac.mm
index 4850c795480..be4f343bcd4 100644
--- a/chromium/ui/display/mac/screen_mac.mm
+++ b/chromium/ui/display/mac/screen_mac.mm
@@ -206,7 +206,7 @@ class ScreenMac : public Screen {
Display GetDisplayNearestView(gfx::NativeView view) const override {
NSWindow* window = [view window];
if (!window)
- window = [NSApp keyWindow];
+ return GetPrimaryDisplay();
return GetDisplayNearestWindow(window);
}
diff --git a/chromium/ui/display/manager/BUILD.gn b/chromium/ui/display/manager/BUILD.gn
index f54a2bbf39d..0b7946e9471 100644
--- a/chromium/ui/display/manager/BUILD.gn
+++ b/chromium/ui/display/manager/BUILD.gn
@@ -36,7 +36,6 @@ jumbo_component("manager") {
"display_manager_export.h",
"display_manager_utilities.cc",
"display_manager_utilities.h",
- "display_pref_util.h",
"fake_display_delegate.cc",
"fake_display_delegate.h",
"fake_display_snapshot.cc",
@@ -59,6 +58,7 @@ jumbo_component("manager") {
"//ui/base",
"//ui/display/mojo:interfaces",
"//ui/display/util",
+ "//ui/events:platform_event",
"//ui/events/devices",
"//ui/strings",
]
diff --git a/chromium/ui/display/manager/chromeos/DEPS b/chromium/ui/display/manager/chromeos/DEPS
index 11d4683fe1f..c11eb4b186c 100644
--- a/chromium/ui/display/manager/chromeos/DEPS
+++ b/chromium/ui/display/manager/chromeos/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+chromeos",
+ "+ui/events/platform_event.h",
# DeviceDataManager is not created in all environments (such as ash when
# running in mus/mash).
"-ui/events/devices/device_data_manager.h",
diff --git a/chromium/ui/display/manager/chromeos/display_change_observer.cc b/chromium/ui/display/manager/chromeos/display_change_observer.cc
index 40a9c7b6835..bf9608d8fc1 100644
--- a/chromium/ui/display/manager/chromeos/display_change_observer.cc
+++ b/chromium/ui/display/manager/chromeos/display_change_observer.cc
@@ -24,6 +24,7 @@
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/util/display_util.h"
+#include "ui/display/util/edid_parser.h"
#include "ui/events/devices/input_device_manager.h"
#include "ui/events/devices/touchscreen_device.h"
#include "ui/strings/grit/ui_strings.h"
@@ -64,6 +65,12 @@ DisplayChangeObserver::GetInternalManagedDisplayModeList(
ui_native_mode->refresh_rate(),
ui_native_mode->is_interlaced(), true, 1.0,
display_info.device_scale_factor());
+ // When display zoom option is available, we cannot change the mode for
+ // internal displays.
+ if (features::IsDisplayZoomSettingEnabled()) {
+ native_mode.set_is_default(true);
+ return ManagedDisplayInfo::ManagedDisplayModeList{native_mode};
+ }
return CreateInternalManagedDisplayModeList(native_mode);
}
@@ -86,13 +93,21 @@ DisplayChangeObserver::GetExternalManagedDisplayModeList(
native_mode = display_mode;
// Add the display mode if it isn't already present and override interlaced
- // display modes with non-interlaced ones.
+ // display modes with non-interlaced ones. We prioritize having non
+ // interlaced mode over refresh rate. A mode having lower refresh rate
+ // but is not interlaced will be picked over a mode having high refresh
+ // rate but is interlaced.
auto display_mode_it = display_mode_map.find(size);
- if (display_mode_it == display_mode_map.end())
+ if (display_mode_it == display_mode_map.end()) {
display_mode_map.insert(std::make_pair(size, display_mode));
- else if (display_mode_it->second.is_interlaced() &&
- !display_mode.is_interlaced())
+ } else if (display_mode_it->second.is_interlaced() &&
+ !display_mode.is_interlaced()) {
+ display_mode_it->second = std::move(display_mode);
+ } else if (!display_mode.is_interlaced() &&
+ display_mode_it->second.refresh_rate() <
+ display_mode.refresh_rate()) {
display_mode_it->second = std::move(display_mode);
+ }
}
ManagedDisplayInfo::ManagedDisplayModeList display_mode_list;
@@ -111,6 +126,11 @@ DisplayChangeObserver::GetExternalManagedDisplayModeList(
display_mode_list.push_back(native_mode);
}
+ // If we are using display zoom mode, we no longer have to add additional
+ // display modes for ultra high resolution displays.
+ if (features::IsDisplayZoomSettingEnabled())
+ return display_mode_list;
+
if (native_mode.size().width() >= kMinimumWidthFor4K) {
for (size_t i = 0; i < arraysize(kAdditionalDeviceScaleFactorsFor4k); ++i) {
ManagedDisplayMode mode(native_mode.size(), native_mode.refresh_rate(),
@@ -247,21 +267,21 @@ void DisplayChangeObserver::UpdateInternalDisplay(
}
ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
- const DisplaySnapshot* state,
+ const DisplaySnapshot* snapshot,
const DisplayMode* mode_info) {
float device_scale_factor = 1.0f;
// Sets dpi only if the screen size is not blacklisted.
- float dpi = IsDisplaySizeBlackListed(state->physical_size())
+ float dpi = IsDisplaySizeBlackListed(snapshot->physical_size())
? 0
: kInchInMm * mode_info->size().width() /
- state->physical_size().width();
+ snapshot->physical_size().width();
- if (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
+ if (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
if (dpi)
device_scale_factor = FindDeviceScaleFactor(dpi);
} else {
ManagedDisplayMode mode;
- if (display_manager_->GetSelectedModeForDisplayId(state->display_id(),
+ if (display_manager_->GetSelectedModeForDisplayId(snapshot->display_id(),
&mode)) {
device_scale_factor = mode.device_scale_factor();
} else {
@@ -270,8 +290,8 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
// from the value of |k2xThreshouldSizeSquaredFor4KInMm|
const int k2xThreshouldSizeSquaredFor4KInMm =
(40 * 40 * kInchInMm * kInchInMm) - 100;
- gfx::Vector2d size_in_vec(state->physical_size().width(),
- state->physical_size().height());
+ gfx::Vector2d size_in_vec(snapshot->physical_size().width(),
+ snapshot->physical_size().height());
if (size_in_vec.LengthSquared() > k2xThreshouldSizeSquaredFor4KInMm &&
mode_info->size().width() >= kMinimumWidthFor4K) {
// Make sure that additional device scale factors table has 2x.
@@ -281,35 +301,47 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
}
}
- std::string name = (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
+ std::string name = (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
? l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL)
- : state->display_name();
+ : snapshot->display_name();
if (name.empty())
name = l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_UNKNOWN);
- const bool has_overscan = state->has_overscan();
- const int64_t id = state->display_id();
+ const bool has_overscan = snapshot->has_overscan();
+ const int64_t id = snapshot->display_id();
ManagedDisplayInfo new_info = ManagedDisplayInfo(id, name, has_overscan);
- new_info.set_sys_path(state->sys_path());
+
+ if (snapshot->product_code() != DisplaySnapshot::kInvalidProductCode) {
+ uint16_t manufacturer_id = 0;
+ uint16_t product_id = 0;
+ EdidParser::SplitProductCodeInManufacturerIdAndProductId(
+ snapshot->product_code(), &manufacturer_id, &product_id);
+ new_info.set_manufacturer_id(
+ EdidParser::ManufacturerIdToString(manufacturer_id));
+ new_info.set_product_id(EdidParser::ProductIdToString(product_id));
+ }
+ new_info.set_year_of_manufacture(snapshot->year_of_manufacture());
+
+ new_info.set_sys_path(snapshot->sys_path());
new_info.set_device_scale_factor(device_scale_factor);
- const gfx::Rect display_bounds(state->origin(), mode_info->size());
+ const gfx::Rect display_bounds(snapshot->origin(), mode_info->size());
new_info.SetBounds(display_bounds);
new_info.set_native(true);
new_info.set_is_aspect_preserving_scaling(
- state->is_aspect_preserving_scaling());
+ snapshot->is_aspect_preserving_scaling());
if (dpi)
new_info.set_device_dpi(dpi);
- new_info.set_color_space(state->color_space());
+ new_info.set_color_space(snapshot->color_space());
ManagedDisplayInfo::ManagedDisplayModeList display_modes =
- (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
- ? GetInternalManagedDisplayModeList(new_info, *state)
- : GetExternalManagedDisplayModeList(*state);
+ (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
+ ? GetInternalManagedDisplayModeList(new_info, *snapshot)
+ : GetExternalManagedDisplayModeList(*snapshot);
new_info.SetManagedDisplayModes(display_modes);
- new_info.set_maximum_cursor_size(state->maximum_cursor_size());
+ new_info.set_maximum_cursor_size(snapshot->maximum_cursor_size());
return new_info;
}
diff --git a/chromium/ui/display/manager/chromeos/display_change_observer.h b/chromium/ui/display/manager/chromeos/display_change_observer.h
index 8ad853d4e40..66cae8da8da 100644
--- a/chromium/ui/display/manager/chromeos/display_change_observer.h
+++ b/chromium/ui/display/manager/chromeos/display_change_observer.h
@@ -64,7 +64,7 @@ class DISPLAY_MANAGER_EXPORT DisplayChangeObserver
void UpdateInternalDisplay(
const DisplayConfigurator::DisplayStateList& display_states);
- ManagedDisplayInfo CreateManagedDisplayInfo(const DisplaySnapshot* state,
+ ManagedDisplayInfo CreateManagedDisplayInfo(const DisplaySnapshot* snapshot,
const DisplayMode* mode_info);
// Both |display_configurator_| and |display_manager_| are not owned and must
diff --git a/chromium/ui/display/manager/chromeos/display_change_observer_unittest.cc b/chromium/ui/display/manager/chromeos/display_change_observer_unittest.cc
index e714181ebd2..7d2922dc9ff 100644
--- a/chromium/ui/display/manager/chromeos/display_change_observer_unittest.cc
+++ b/chromium/ui/display/manager/chromeos/display_change_observer_unittest.cc
@@ -6,8 +6,9 @@
#include <string>
-#include "base/memory/ptr_util.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/display_switches.h"
#include "ui/display/manager/chromeos/display_configurator.h"
#include "ui/display/manager/fake_display_snapshot.h"
#include "ui/display/manager/managed_display_info.h"
@@ -38,7 +39,23 @@ std::unique_ptr<DisplayMode> MakeDisplayMode(int width,
} // namespace
-TEST(DisplayChangeObserverTest, GetExternalManagedDisplayModeList) {
+class DisplayChangeObserverTest : public testing::Test {
+ public:
+ DisplayChangeObserverTest() = default;
+
+ void SetUp() override {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kEnableDisplayZoomSetting);
+ testing::Test::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayChangeObserverTest);
+};
+
+TEST_F(DisplayChangeObserverTest, GetExternalManagedDisplayModeList) {
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
@@ -90,7 +107,7 @@ TEST(DisplayChangeObserverTest, GetExternalManagedDisplayModeList) {
EXPECT_EQ(display_modes[5].refresh_rate(), 60);
}
-TEST(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) {
+TEST_F(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) {
FakeDisplaySnapshot display_snapshot(
123, gfx::Point(), gfx::Size(), DISPLAY_CONNECTION_TYPE_UNKNOWN, false,
false, false, std::string(), {}, nullptr, nullptr, 0, gfx::Size());
@@ -101,7 +118,7 @@ TEST(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) {
EXPECT_EQ(0u, display_modes.size());
}
-TEST(DisplayChangeObserverTest, GetInternalManagedDisplayModeList) {
+TEST_F(DisplayChangeObserverTest, GetInternalManagedDisplayModeList) {
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
@@ -145,7 +162,7 @@ TEST(DisplayChangeObserverTest, GetInternalManagedDisplayModeList) {
EXPECT_EQ(display_modes[4].refresh_rate(), 60);
}
-TEST(DisplayChangeObserverTest, GetInternalHiDPIManagedDisplayModeList) {
+TEST_F(DisplayChangeObserverTest, GetInternalHiDPIManagedDisplayModeList) {
// Data picked from peppy.
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
@@ -204,7 +221,7 @@ TEST(DisplayChangeObserverTest, GetInternalHiDPIManagedDisplayModeList) {
EXPECT_EQ(display_modes[7].refresh_rate(), 60);
}
-TEST(DisplayChangeObserverTest, GetInternalManagedDisplayModeList1_25) {
+TEST_F(DisplayChangeObserverTest, GetInternalManagedDisplayModeList1_25) {
// Data picked from peppy.
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
@@ -246,7 +263,7 @@ TEST(DisplayChangeObserverTest, GetInternalManagedDisplayModeList1_25) {
EXPECT_EQ(display_modes[4].refresh_rate(), 60);
}
-TEST(DisplayChangeObserverTest, GetExternalManagedDisplayModeList4K) {
+TEST_F(DisplayChangeObserverTest, GetExternalManagedDisplayModeList4K) {
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
@@ -320,7 +337,7 @@ TEST(DisplayChangeObserverTest, GetExternalManagedDisplayModeList4K) {
EXPECT_EQ(display_modes[8].refresh_rate(), 30);
}
-TEST(DisplayChangeObserverTest, FindDeviceScaleFactor) {
+TEST_F(DisplayChangeObserverTest, FindDeviceScaleFactor) {
EXPECT_EQ(1.0f, ComputeDeviceScaleFactor(19.5f, gfx::Rect(1600, 900)));
// 21.5" 1920x1080
@@ -353,7 +370,8 @@ TEST(DisplayChangeObserverTest, FindDeviceScaleFactor) {
EXPECT_EQ(2.0f, DisplayChangeObserver::FindDeviceScaleFactor(10000.0f));
}
-TEST(DisplayChangeObserverTest, FindExternalDisplayNativeModeWhenOverwritten) {
+TEST_F(DisplayChangeObserverTest,
+ FindExternalDisplayNativeModeWhenOverwritten) {
std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
diff --git a/chromium/ui/display/manager/chromeos/display_configurator.cc b/chromium/ui/display/manager/chromeos/display_configurator.cc
index b077a4b25db..e939dbac1f5 100644
--- a/chromium/ui/display/manager/chromeos/display_configurator.cc
+++ b/chromium/ui/display/manager/chromeos/display_configurator.cc
@@ -11,7 +11,6 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "chromeos/system/devicemode.h"
#include "ui/display/display.h"
@@ -504,7 +503,6 @@ DisplayConfigurator::DisplayConfigurator()
current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
- requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
pending_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
has_pending_power_state_(false),
pending_power_flags_(kSetDisplayPowerNoFlags),
@@ -547,9 +545,25 @@ void DisplayConfigurator::SetDelegateForTesting(
void DisplayConfigurator::SetInitialDisplayPower(
chromeos::DisplayPowerState power_state) {
- DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
- requested_power_state_ = current_power_state_ = power_state;
- NotifyPowerStateObservers();
+ if (requested_power_state_) {
+ // A new power state has alreday been requested so ignore the initial state.
+ return;
+ }
+
+ // Set the initial requested power state.
+ requested_power_state_ = power_state;
+
+ if (current_display_state_ == MULTIPLE_DISPLAY_STATE_INVALID) {
+ // DisplayConfigurator::OnConfigured has not been called yet so just set
+ // the current state and notify observers.
+ current_power_state_ = power_state;
+ NotifyPowerStateObservers();
+ return;
+ }
+
+ // DisplayConfigurator::OnConfigured has been called so update the current
+ // and pending states.
+ UpdatePowerState(power_state);
}
void DisplayConfigurator::Init(
@@ -591,9 +605,11 @@ void DisplayConfigurator::OnDisplayControlTaken(DisplayControlCallback callback,
if (success) {
// Force a configuration since the display configuration may have changed.
force_configure_ = true;
- // Restore the last power state used before releasing control.
- SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags,
- base::DoNothing());
+ if (requested_power_state_) {
+ // Restore the requested power state before releasing control.
+ SetDisplayPower(*requested_power_state_, kSetDisplayPowerNoFlags,
+ base::DoNothing());
+ }
}
std::move(callback).Run(success);
@@ -668,8 +684,8 @@ void DisplayConfigurator::ForceInitialConfigure() {
configuration_task_.reset(new UpdateDisplayConfigurationTask(
native_display_delegate_.get(), layout_manager_.get(),
- requested_display_state_, requested_power_state_,
- kSetDisplayPowerForceProbe, true,
+ requested_display_state_, GetRequestedPowerState(),
+ kSetDisplayPowerForceProbe, /*force_configure=*/true,
base::Bind(&DisplayConfigurator::OnConfigured,
weak_ptr_factory_.GetWeakPtr())));
configuration_task_->Run();
@@ -849,15 +865,29 @@ bool DisplayConfigurator::SetColorCorrection(
const std::vector<GammaRampRGBEntry>& degamma_lut,
const std::vector<GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix) {
- for (const DisplaySnapshot* display : cached_displays_) {
- if (display->display_id() == display_id)
- return native_display_delegate_->SetColorCorrection(
- *display, degamma_lut, gamma_lut, correction_matrix);
+ for (DisplaySnapshot* display : cached_displays_) {
+ if (display->display_id() != display_id)
+ continue;
+
+ const bool success = native_display_delegate_->SetColorCorrection(
+ *display, degamma_lut, gamma_lut, correction_matrix);
+ // Nullify the |display|s ColorSpace to avoid correcting colors twice, if
+ // we have successfully configured something.
+ if (success && (!degamma_lut.empty() || !gamma_lut.empty() ||
+ !correction_matrix.empty())) {
+ display->reset_color_space();
+ }
+ return success;
}
return false;
}
+chromeos::DisplayPowerState DisplayConfigurator::GetRequestedPowerState()
+ const {
+ return requested_power_state_.value_or(chromeos::DISPLAY_POWER_ALL_ON);
+}
+
void DisplayConfigurator::PrepareForExit() {
configure_display_ = false;
}
@@ -909,7 +939,7 @@ void DisplayConfigurator::SetDisplayPower(
<< (configure_timer_.IsRunning() ? "Running" : "Stopped");
requested_power_state_ = power_state;
- SetDisplayPowerInternal(requested_power_state_, flags, callback);
+ SetDisplayPowerInternal(*requested_power_state_, flags, callback);
}
void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
@@ -1007,8 +1037,10 @@ void DisplayConfigurator::ResumeDisplays() {
// If requested_power_state_ is ALL_OFF due to idle suspend, powerd will turn
// the display power on when it enables the backlight.
- SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags,
- base::DoNothing());
+ if (requested_power_state_) {
+ SetDisplayPower(*requested_power_state_, kSetDisplayPowerNoFlags,
+ base::DoNothing());
+ }
}
void DisplayConfigurator::ConfigureDisplays() {
@@ -1063,19 +1095,8 @@ void DisplayConfigurator::OnConfigured(
cached_displays_ = displays;
if (success) {
- chromeos::DisplayPowerState old_power_state = current_power_state_;
current_display_state_ = new_display_state;
- current_power_state_ = new_power_state;
-
- // If the pending power state hasn't changed then make sure that value
- // gets updated as well since the last requested value may have been
- // dependent on certain conditions (ie: if only the internal monitor was
- // present).
- if (!has_pending_power_state_)
- pending_power_state_ = new_power_state;
-
- if (old_power_state != current_power_state_)
- NotifyPowerStateObservers();
+ UpdatePowerState(new_power_state);
}
configuration_task_.reset();
@@ -1095,6 +1116,19 @@ void DisplayConfigurator::OnConfigured(
}
}
+void DisplayConfigurator::UpdatePowerState(
+ chromeos::DisplayPowerState new_power_state) {
+ chromeos::DisplayPowerState old_power_state = current_power_state_;
+ current_power_state_ = new_power_state;
+ // If the pending power state hasn't changed then make sure that value gets
+ // updated as well since the last requested value may have been dependent on
+ // certain conditions (ie: if only the internal monitor was present).
+ if (!has_pending_power_state_)
+ pending_power_state_ = new_power_state;
+ if (old_power_state != current_power_state_)
+ NotifyPowerStateObservers();
+}
+
bool DisplayConfigurator::ShouldRunConfigurationTask() const {
if (force_configure_)
return true;
diff --git a/chromium/ui/display/manager/chromeos/display_configurator.h b/chromium/ui/display/manager/chromeos/display_configurator.h
index fe91b2ca336..3087d989592 100644
--- a/chromium/ui/display/manager/chromeos/display_configurator.h
+++ b/chromium/ui/display/manager/chromeos/display_configurator.h
@@ -13,10 +13,10 @@
#include <vector>
#include "base/containers/queue.h"
-#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/optional.h"
#include "base/timer/timer.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/display/manager/chromeos/query_content_protection_task.h"
@@ -24,6 +24,7 @@
#include "ui/display/types/display_constants.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/display/util/display_util.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/geometry/size.h"
namespace gfx {
@@ -179,9 +180,6 @@ class DISPLAY_MANAGER_EXPORT DisplayConfigurator
~DisplayConfigurator() override;
MultipleDisplayState display_state() const { return current_display_state_; }
- chromeos::DisplayPowerState requested_power_state() const {
- return requested_power_state_;
- }
const std::vector<DisplaySnapshot*>& cached_displays() const {
return cached_displays_;
}
@@ -211,7 +209,11 @@ class DISPLAY_MANAGER_EXPORT DisplayConfigurator
void SetDelegateForTesting(
std::unique_ptr<NativeDisplayDelegate> display_delegate);
- // Sets the initial value of |power_state_|. Must be called before Start().
+ // Called asynchronously with the initial |power_state| loaded from prefs.
+ // This may be called after ForceInitialConfigure triggers a call to
+ // OnConfigured(), in which case UpdatePowerState() will be called with the
+ // correct initial value. Does nothing if |requested_power_state_| is set,
+ // e.g. via SetDisplayPower().
void SetInitialDisplayPower(chromeos::DisplayPowerState power_state);
// Initialization, must be called right after constructor.
@@ -289,6 +291,9 @@ class DISPLAY_MANAGER_EXPORT DisplayConfigurator
const std::vector<GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix);
+ // Returns the requested power state if set or the default power state.
+ chromeos::DisplayPowerState GetRequestedPowerState() const;
+
void set_is_multi_mirroring_enabled_for_test(bool enabled) {
is_multi_mirroring_enabled_ = enabled;
}
@@ -334,6 +339,9 @@ class DISPLAY_MANAGER_EXPORT DisplayConfigurator
MultipleDisplayState new_display_state,
chromeos::DisplayPowerState new_power_state);
+ // Updates the current and pending power state and notifies observers.
+ void UpdatePowerState(chromeos::DisplayPowerState new_power_state);
+
// Helps in identifying if a configuration task needs to be scheduled.
// Return true if any of the |requested_*| parameters have been updated. False
// otherwise.
@@ -395,7 +403,7 @@ class DISPLAY_MANAGER_EXPORT DisplayConfigurator
MultipleDisplayState requested_display_state_;
// Stores the requested power state.
- chromeos::DisplayPowerState requested_power_state_;
+ base::Optional<chromeos::DisplayPowerState> requested_power_state_;
// The power state used by RunPendingConfiguration(). May be
// |requested_power_state_| or DISPLAY_POWER_ALL_OFF for suspend.
diff --git a/chromium/ui/display/manager/chromeos/display_configurator_unittest.cc b/chromium/ui/display/manager/chromeos/display_configurator_unittest.cc
index 987977c2295..623add64ef4 100644
--- a/chromium/ui/display/manager/chromeos/display_configurator_unittest.cc
+++ b/chromium/ui/display/manager/chromeos/display_configurator_unittest.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "chromeos/chromeos_switches.cc"
@@ -686,6 +685,12 @@ TEST_F(DisplayConfiguratorTest, SetDisplayPower) {
TEST_F(DisplayConfiguratorTest, SuspendAndResume) {
InitWithSingleOutput();
+ // Set the initial power state to on.
+ config_waiter_.Reset();
+ configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
+ DisplayConfigurator::kSetDisplayPowerNoFlags,
+ config_waiter_.on_configuration_callback());
+
// No preparation is needed before suspending when the display is already
// on. The configurator should still reprobe on resume in case a display
// was connected while suspended.
@@ -1406,9 +1411,17 @@ TEST_F(DisplayConfiguratorTest, DontRestoreStalePowerStateAfterResume) {
TEST_F(DisplayConfiguratorTest, ExternalControl) {
InitWithSingleOutput();
state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE);
+
+ // Set the initial power state and verify that it is restored when control is
+ // taken.
+ config_waiter_.Reset();
+ configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
+ DisplayConfigurator::kSetDisplayPowerNoFlags,
+ config_waiter_.on_configuration_callback());
+
configurator_.RelinquishControl(
- base::Bind(&DisplayConfiguratorTest::OnDisplayControlUpdated,
- base::Unretained(this)));
+ base::BindOnce(&DisplayConfiguratorTest::OnDisplayControlUpdated,
+ base::Unretained(this)));
EXPECT_EQ(CALLBACK_SUCCESS, PopDisplayControlResult());
EXPECT_EQ(
JoinActions(
@@ -1416,8 +1429,8 @@ TEST_F(DisplayConfiguratorTest, ExternalControl) {
kRelinquishDisplayControl, nullptr),
log_->GetActionsAndClear());
configurator_.TakeControl(
- base::Bind(&DisplayConfiguratorTest::OnDisplayControlUpdated,
- base::Unretained(this)));
+ base::BindOnce(&DisplayConfiguratorTest::OnDisplayControlUpdated,
+ base::Unretained(this)));
EXPECT_EQ(CALLBACK_SUCCESS, PopDisplayControlResult());
EXPECT_EQ(
JoinActions(
@@ -1652,6 +1665,13 @@ TEST_F(DisplayConfiguratorTest, TestWithThreeDisplays) {
// Tests the suspend and resume behavior when in dual or multi display modes.
TEST_F(DisplayConfiguratorTest, SuspendResumeWithMultipleDisplays) {
InitWithSingleOutput();
+
+ // Set the initial power state and verify that it is restored on resume.
+ config_waiter_.Reset();
+ configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
+ DisplayConfigurator::kSetDisplayPowerNoFlags,
+ config_waiter_.on_configuration_callback());
+
state_controller_.set_state(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED);
observer_.Reset();
UpdateOutputs(2, true);
diff --git a/chromium/ui/display/manager/chromeos/display_util.cc b/chromium/ui/display/manager/chromeos/display_util.cc
index acf2084a8ee..b6e66143748 100644
--- a/chromium/ui/display/manager/chromeos/display_util.cc
+++ b/chromium/ui/display/manager/chromeos/display_util.cc
@@ -5,13 +5,32 @@
#include "ui/display/manager/chromeos/display_util.h"
#include <stddef.h>
+#include <algorithm>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "ui/display/manager/managed_display_info.h"
#include "ui/display/types/display_snapshot.h"
namespace display {
+namespace {
+
+// The list of deltas between two consecutive zoom level. Any display must have
+// one of these values as the difference between two consecutive zoom level.
+constexpr std::array<double, 7> kZoomFactorDeltas = {0.05f, 0.1f, 0.15f, 0.2f,
+ 0.25f, 0.5f, 1.f};
+
+// The maximum logical resolution width allowed when zooming out for a display.
+constexpr int kDefaultMaxZoomWidth = 4096;
+
+// The minimum logical resolution width allowed when zooming in for a display.
+constexpr int kDefaultMinZoomWidth = 640;
+
+// The total number of display zoom factors to enumerate.
+constexpr int kNumOfZoomFactors = 9;
+
+} // namespace
std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) {
switch (state) {
@@ -71,4 +90,61 @@ bool IsPhysicalDisplayType(DisplayConnectionType type) {
return !(type & DISPLAY_CONNECTION_TYPE_NETWORK);
}
+std::vector<double> GetDisplayZoomFactors(const ManagedDisplayMode& mode) {
+ const int effective_width = std::round(
+ static_cast<float>(mode.size().width()) / mode.device_scale_factor());
+
+ // We want to support displays greater than 4K. This is added to ensure the
+ // zoom does not break in such cases.
+ const int max_width = std::max(effective_width, kDefaultMaxZoomWidth);
+ const int min_width = std::min(effective_width, kDefaultMinZoomWidth);
+
+ // The logical resolution will vary from half of the mode resolution to double
+ // the mode resolution.
+ int max_effective_width =
+ std::min(static_cast<int>(std::round(effective_width * 2.f)), max_width);
+ int min_effective_width =
+ std::max(static_cast<int>(std::round(effective_width / 2.f)), min_width);
+
+ // If either the maximum width or minimum width was reached in the above step
+ // and clamping was performed, then update the total range of logical
+ // resolutions and ensure that everything lies within the maximum and minimum
+ // resolution range.
+ const int interval = std::round(static_cast<double>(effective_width) * 1.5f);
+ if (max_effective_width == max_width)
+ min_effective_width = std::max(max_effective_width - interval, min_width);
+ if (min_effective_width == min_width)
+ max_effective_width = std::min(min_effective_width + interval, max_width);
+
+ double max_zoom = static_cast<double>(effective_width) /
+ static_cast<double>(min_effective_width);
+ double min_zoom = static_cast<double>(effective_width) /
+ static_cast<double>(max_effective_width);
+
+ double delta =
+ (max_zoom - min_zoom) / static_cast<double>(kNumOfZoomFactors - 1);
+
+ // Number of zoom values above 100% zoom.
+ const int zoom_in_count = std::round((max_zoom - 1.f) / delta);
+
+ // Number of zoom values below 100% zoom.
+ const int zoom_out_count = kNumOfZoomFactors - zoom_in_count - 1;
+
+ // Clamp the delta between consecutive zoom factors to a user friendly and UI
+ // friendly value.
+ std::size_t delta_index = 0;
+ while (delta_index < kZoomFactorDeltas.size() &&
+ delta >= kZoomFactorDeltas[delta_index]) {
+ delta_index++;
+ }
+ delta = kZoomFactorDeltas[delta_index - 1];
+
+ min_zoom = 1.f - delta * zoom_out_count;
+
+ std::vector<double> zoom_values;
+ for (int i = 0; i < kNumOfZoomFactors; i++)
+ zoom_values.push_back(min_zoom + i * delta);
+ return zoom_values;
+}
+
} // namespace display
diff --git a/chromium/ui/display/manager/chromeos/display_util.h b/chromium/ui/display/manager/chromeos/display_util.h
index 3da69e16416..0f04c816392 100644
--- a/chromium/ui/display/manager/chromeos/display_util.h
+++ b/chromium/ui/display/manager/chromeos/display_util.h
@@ -15,6 +15,7 @@
namespace display {
class DisplaySnapshot;
+class ManagedDisplayMode;
// Returns a string describing |state|.
std::string DisplayPowerStateToString(chromeos::DisplayPowerState state);
@@ -35,6 +36,10 @@ GetDisplayPower(const std::vector<DisplaySnapshot*>& displays,
// All other types return true.
bool IsPhysicalDisplayType(DisplayConnectionType type);
+// Returns a list of display zooms supported by the given |mode|.
+std::vector<double> DISPLAY_MANAGER_EXPORT
+GetDisplayZoomFactors(const ManagedDisplayMode& mode);
+
} // namespace display
#endif // UI_DISPLAY_MANAGER_CHROMEOS_DISPLAY_UTIL_H_
diff --git a/chromium/ui/display/manager/chromeos/display_utils_unittest.cc b/chromium/ui/display/manager/chromeos/display_utils_unittest.cc
new file mode 100644
index 00000000000..0eeb386e003
--- /dev/null
+++ b/chromium/ui/display/manager/chromeos/display_utils_unittest.cc
@@ -0,0 +1,111 @@
+// 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/display/manager/chromeos/display_util.h"
+
+#include <vector>
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/manager/managed_display_info.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace display {
+namespace test {
+
+namespace {
+constexpr std::size_t kNumOfZoomFactors = 9;
+constexpr int kDefaultMaxZoomWidth = 4096;
+constexpr int kDefaultMinZoomWidth = 640;
+} // namespace
+using DisplayUtilTest = testing::Test;
+
+TEST_F(DisplayUtilTest, DisplayZooms) {
+ // A vector of pairs where each pair is the resolution width correspoinding
+ // to its list of available display zoom values.
+ const std::vector<std::pair<int, std::vector<double>>> expected_zoom_values{
+ {480, {0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.f}},
+ {640, {0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.f}},
+ {720, {0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.f, 1.05f}},
+ {800, {0.40f, 0.50f, 0.60f, 0.70f, 0.80f, 0.90f, 1.f, 1.10f, 1.20f}},
+ {960, {0.60f, 0.70f, 0.80f, 0.90f, 1.f, 1.10f, 1.20f, 1.30f, 1.40f}},
+ {1024, {0.60f, 0.70f, 0.80f, 0.90f, 1.f, 1.10f, 1.20f, 1.30f, 1.40f}},
+ {1280, {0.55f, 0.70f, 0.85f, 1.f, 1.15f, 1.30f, 1.45f, 1.60f, 1.75f}},
+ {1366, {0.55f, 0.70f, 0.85f, 1.f, 1.15f, 1.30f, 1.45f, 1.60f, 1.75f}},
+ {1440, {0.55f, 0.70f, 0.85f, 1.f, 1.15f, 1.30f, 1.45f, 1.60f, 1.75f}},
+ {1600, {0.55f, 0.70f, 0.85f, 1.f, 1.15f, 1.30f, 1.45f, 1.60f, 1.75f}},
+ {1920, {0.55f, 0.70f, 0.85f, 1.f, 1.15f, 1.30f, 1.45f, 1.60f, 1.75f}},
+ {2160, {0.60f, 0.80f, 1.f, 1.20f, 1.40f, 1.60f, 1.80f, 2.00f, 2.20f}},
+ {2560, {0.75f, 1.f, 1.25f, 1.50f, 1.75f, 2.00f, 2.25f, 2.50f, 2.75f}},
+ {2880, {0.75f, 1.f, 1.25f, 1.50f, 1.75f, 2.00f, 2.25f, 2.50f, 2.75f}},
+ {3200, {1.f, 1.50f, 2.00f, 2.50f, 3.00f, 3.50f, 4.00f, 4.50f, 5.00f}},
+ {3840, {1.f, 1.50f, 2.00f, 2.50f, 3.00f, 3.50f, 4.00f, 4.50f, 5.00f}},
+ {4096, {1.f, 1.50f, 2.00f, 2.50f, 3.00f, 3.50f, 4.00f, 4.50f, 5.00f}},
+ {5120, {1.f, 1.50f, 2.00f, 2.50f, 3.00f, 3.50f, 4.00f, 4.50f, 5.00f}},
+ {7680, {1.f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, 9.00f}},
+ {8192, {1.f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, 9.00f}},
+ };
+
+ for (const auto& pair : expected_zoom_values) {
+ const int size = pair.first;
+ ManagedDisplayMode mode(gfx::Size(size, size), 60, false, true, 1.f, 1.f);
+ const std::vector<double> zoom_values = GetDisplayZoomFactors(mode);
+ EXPECT_EQ(zoom_values.size(), kNumOfZoomFactors);
+ for (std::size_t j = 0; j < kNumOfZoomFactors; j++) {
+ EXPECT_NEAR(zoom_values[j], pair.second[j], 0.001);
+
+ // Display pref stores the zoom value only upto 2 decimal places. This
+ // check ensures that the expected precision is only upto 2 decimal
+ // points. Before changing this line please ensure that you have updated
+ // chromeos/display/display_prefs.cc
+ int percentage_value = std::round(zoom_values[j] * 100.f);
+ float fractional_value = static_cast<float>(percentage_value) / 100.f;
+ EXPECT_NEAR(zoom_values[j], fractional_value, 0.0001f);
+ }
+
+ const int effective_minimum_width_possible = size / zoom_values.back();
+ const int effective_maximum_width_possible = size * zoom_values.front();
+
+ const int allowed_minimum_width = std::min(kDefaultMinZoomWidth, size);
+ const int allowed_maximum_width = std::max(kDefaultMaxZoomWidth, size);
+
+ EXPECT_GE(effective_minimum_width_possible, allowed_minimum_width);
+ EXPECT_LE(effective_maximum_width_possible, allowed_maximum_width);
+ }
+}
+
+TEST_F(DisplayUtilTest, DisplayZoomsWithInternalDsf) {
+ const std::vector<int> sizes = {1280, 1366, 1440, 1600, 1920, 2160, 2560,
+ 2880, 3200, 3840, 4096, 5120, 7680, 8192};
+
+ const std::vector<float> dsfs = {1.25f, 1.5f, 1.6f, 1.8f, 2.f, 2.25f};
+
+ for (float dsf : dsfs) {
+ for (int size : sizes) {
+ ManagedDisplayMode mode(gfx::Size(size, size), 60, false, true, 1.f, dsf);
+ const std::vector<double> zoom_values = GetDisplayZoomFactors(mode);
+
+ const int effective_size = std::round(static_cast<float>(size) / dsf);
+ ManagedDisplayMode expected_mode(
+ gfx::Size(effective_size, effective_size), 60, false, true, 1.f, 1.f);
+ const std::vector<double> expected_zoom_values =
+ GetDisplayZoomFactors(expected_mode);
+ EXPECT_EQ(zoom_values.size(), kNumOfZoomFactors);
+ for (std::size_t i = 0; i < kNumOfZoomFactors; i++)
+ EXPECT_NEAR(zoom_values[i], expected_zoom_values[i], 0.001);
+
+ const int effective_minimum_width_possible = size / zoom_values.back();
+ const int effective_maximum_width_possible = size * zoom_values.front();
+
+ const int allowed_minimum_width = std::min(kDefaultMinZoomWidth, size);
+ const int allowed_maximum_width = std::max(kDefaultMaxZoomWidth, size);
+
+ EXPECT_GE(effective_minimum_width_possible, allowed_minimum_width);
+ EXPECT_LE(effective_maximum_width_possible, allowed_maximum_width);
+ }
+ }
+}
+
+} // namespace test
+} // namespace display
diff --git a/chromium/ui/display/manager/chromeos/touch_device_manager.cc b/chromium/ui/display/manager/chromeos/touch_device_manager.cc
index 4ffd851a402..656fe1db54e 100644
--- a/chromium/ui/display/manager/chromeos/touch_device_manager.cc
+++ b/chromium/ui/display/manager/chromeos/touch_device_manager.cc
@@ -5,7 +5,9 @@
#include "ui/display/manager/chromeos/touch_device_manager.h"
#include <algorithm>
+#include <set>
#include <string>
+#include <tuple>
#include "base/files/file_util.h"
#include "base/hash.h"
@@ -24,6 +26,7 @@ using ManagedDisplayInfoList = std::vector<ManagedDisplayInfo*>;
using DeviceList = std::vector<ui::TouchscreenDevice>;
constexpr char kFallbackTouchDeviceName[] = "fallback_touch_device_name";
+constexpr char kFallbackTouchDevicePhys[] = "fallback_touch_device_phys";
// Returns true if |path| is likely a USB device.
bool IsDeviceConnectedViaUsb(const base::FilePath& path) {
@@ -145,6 +148,23 @@ ManagedDisplayInfo* GetBestMatchForDevice(
return display_info;
}
+// Returns a set of TouchDeviceIdentifiers (sans their port information) that
+// are associated with more than 1 touch device from the list |devices|.
+std::set<TouchDeviceIdentifier, TouchDeviceIdentifier::WeakComp>
+GetCollisionSet(const DeviceList& devices) {
+ std::set<TouchDeviceIdentifier, TouchDeviceIdentifier::WeakComp>
+ collision_set;
+ std::set<TouchDeviceIdentifier, TouchDeviceIdentifier::WeakComp> ids;
+ for (const ui::TouchscreenDevice& device : devices) {
+ TouchDeviceIdentifier id = TouchDeviceIdentifier::FromDevice(device);
+ if (ids.find(id) != ids.end())
+ collision_set.insert(id);
+ else
+ ids.insert(id);
+ }
+ return collision_set;
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -154,7 +174,8 @@ ManagedDisplayInfo* GetBestMatchForDevice(
const TouchDeviceIdentifier&
TouchDeviceIdentifier::GetFallbackTouchDeviceIdentifier() {
static const TouchDeviceIdentifier kFallTouchDeviceIdentifier(
- GenerateIdentifier(kFallbackTouchDeviceName, 0, 0));
+ GenerateIdentifier(kFallbackTouchDeviceName, 0, 0),
+ base::PersistentHash(kFallbackTouchDevicePhys));
return kFallTouchDeviceIdentifier;
}
@@ -170,28 +191,36 @@ uint32_t TouchDeviceIdentifier::GenerateIdentifier(std::string name,
// static
TouchDeviceIdentifier TouchDeviceIdentifier::FromDevice(
const ui::TouchscreenDevice& touch_device) {
- return TouchDeviceIdentifier(GenerateIdentifier(
- touch_device.name, touch_device.vendor_id, touch_device.product_id));
+ return TouchDeviceIdentifier(
+ GenerateIdentifier(touch_device.name, touch_device.vendor_id,
+ touch_device.product_id),
+ base::PersistentHash(touch_device.phys));
}
TouchDeviceIdentifier::TouchDeviceIdentifier(uint32_t identifier)
- : id_(identifier) {}
+ : id_(identifier),
+ secondary_id_(base::PersistentHash(kFallbackTouchDevicePhys)) {}
+
+TouchDeviceIdentifier::TouchDeviceIdentifier(uint32_t identifier,
+ uint32_t secondary_id)
+ : id_(identifier), secondary_id_(secondary_id) {}
TouchDeviceIdentifier::TouchDeviceIdentifier(const TouchDeviceIdentifier& other)
- : id_(other.id_) {}
+ : id_(other.id_), secondary_id_(other.secondary_id_) {}
TouchDeviceIdentifier& TouchDeviceIdentifier::operator=(
TouchDeviceIdentifier other) {
id_ = other.id_;
+ secondary_id_ = other.secondary_id_;
return *this;
}
bool TouchDeviceIdentifier::operator<(const TouchDeviceIdentifier& rhs) const {
- return id_ < rhs.id_;
+ return std::tie(id_, secondary_id_) < std::tie(rhs.id_, rhs.secondary_id_);
}
bool TouchDeviceIdentifier::operator==(const TouchDeviceIdentifier& rhs) const {
- return id_ == rhs.id_;
+ return id_ == rhs.id_ && secondary_id_ == rhs.secondary_id_;
}
bool TouchDeviceIdentifier::operator!=(const TouchDeviceIdentifier& rhs) const {
@@ -202,6 +231,10 @@ std::string TouchDeviceIdentifier::ToString() const {
return base::UintToString(id_);
}
+std::string TouchDeviceIdentifier::SecondaryIdToString() const {
+ return base::UintToString(secondary_id_);
+}
+
////////////////////////////////////////////////////////////////////////////////
// TouchCalibrationData
@@ -255,6 +288,7 @@ TouchDeviceManager::~TouchDeviceManager() {}
void TouchDeviceManager::AssociateTouchscreens(
std::vector<ManagedDisplayInfo>* all_displays,
const std::vector<ui::TouchscreenDevice>& all_devices) {
+ active_touch_associations_.clear();
// |displays| and |devices| contain pointers directly to the values stored
// inside of |all_displays| and |all_devices|. When a display or input device
// has been associated, it is removed from the |displays| or |devices| list.
@@ -286,6 +320,7 @@ void TouchDeviceManager::AssociateTouchscreens(
}
AssociateInternalDevices(&displays, &devices);
+ AssociateDevicesWithCollision(&displays, &devices);
AssociateFromHistoricalData(&displays, &devices);
AssociateUdlDevices(&displays, &devices);
AssociateSameSizeDevices(&displays, &devices);
@@ -341,6 +376,54 @@ void TouchDeviceManager::AssociateInternalDevices(
}
}
+void TouchDeviceManager::AssociateDevicesWithCollision(
+ ManagedDisplayInfoList* displays,
+ DeviceList* devices) {
+ if (!devices->size() || !displays->size())
+ return;
+
+ // Get a list of touch devices that have the same primary ids but connected
+ // via different interfaces.
+ std::set<TouchDeviceIdentifier, TouchDeviceIdentifier::WeakComp>
+ collision_set = GetCollisionSet(*devices);
+ if (collision_set.empty())
+ return;
+
+ VLOG(2) << "Trying to match " << devices->size() << " devices "
+ << "and " << displays->size() << " displays where there is/are "
+ << collision_set.size() << " collisions with the touch device ids";
+
+ for (auto device_it = devices->begin(); device_it != devices->end();) {
+ const auto identifier = TouchDeviceIdentifier::FromDevice(*device_it);
+ // If this device is not the one that has a collision or if this device is
+ // the one that has collision but we have no past port mapping information
+ // associated with it, then we skip.
+ if (!base::ContainsKey(collision_set, identifier) ||
+ !base::ContainsKey(port_associations_, identifier)) {
+ device_it++;
+ continue;
+ }
+
+ int64_t display_id = port_associations_.at(identifier);
+
+ // Find the display associated with |display_id| from |displays|.
+ ManagedDisplayInfoList::iterator display_it =
+ std::find_if(displays->begin(), displays->end(),
+ [&display_id](ManagedDisplayInfo* info) {
+ return info->id() == display_id;
+ });
+
+ if (display_it != displays->end()) {
+ VLOG(2) << "=> Matched device " << (*device_it).name << " to display "
+ << (*display_it)->name();
+ Associate(*display_it, *device_it);
+ device_it = devices->erase(device_it);
+ } else {
+ device_it++;
+ }
+ }
+}
+
void TouchDeviceManager::AssociateFromHistoricalData(
ManagedDisplayInfoList* displays,
DeviceList* devices) {
@@ -531,6 +614,11 @@ void TouchDeviceManager::AddTouchCalibrationData(
info.calibration_data = data;
touch_associations_.at(identifier).emplace(display_id, info);
}
+
+ // Store the port association information, i.e. the touch device identified by
+ // |identifier| when connected to port |identifier.secondary_id()| was
+ // associated with display identified by |display_id|.
+ port_associations_[identifier] = display_id;
}
void TouchDeviceManager::ClearTouchCalibrationData(
@@ -612,13 +700,16 @@ TouchDeviceManager::GetAssociatedTouchDevicesForDisplay(
}
void TouchDeviceManager::RegisterTouchAssociations(
- const TouchAssociationMap& touch_associations) {
+ const TouchAssociationMap& touch_associations,
+ const PortAssociationMap& port_associations) {
touch_associations_ = touch_associations;
+ port_associations_ = port_associations;
}
std::ostream& operator<<(std::ostream& os,
const TouchDeviceIdentifier& identifier) {
- return os << identifier.ToString();
+ return os << identifier.ToString() << " [" << identifier.SecondaryIdToString()
+ << "]";
}
bool HasExternalTouchscreenDevice() {
diff --git a/chromium/ui/display/manager/chromeos/touch_device_manager.h b/chromium/ui/display/manager/chromeos/touch_device_manager.h
index 5c42e66cdb9..e64cd187a61 100644
--- a/chromium/ui/display/manager/chromeos/touch_device_manager.h
+++ b/chromium/ui/display/manager/chromeos/touch_device_manager.h
@@ -28,10 +28,29 @@ namespace test {
class TouchDeviceManagerTestApi;
} // namespace test
-// A unique identifier to identify |ui::TouchscreenDevices|. These identifiers
-// are persistent across system restarts.
+// A unique identifier to identify |ui::TouchscreenDevices|. The primary id
+// reflected by |id_| is persistent across system restarts and hotplugs. The
+// secondary id represented by |secondary_id_|, reflects the physical port
+// information. This is consistent and safe as long as the device is connected
+// to the same port along the same path.
class DISPLAY_MANAGER_EXPORT TouchDeviceIdentifier {
public:
+ // A comparator that does not differentiate between duplicate instances of
+ // the same kind of touch devices, i.e. devices with the same primary id.
+ // Use this when you are working with different kinds of devices and do not
+ // care about multiple instances of the same kind of device.
+ // For example; if you want to store all the calibration information for
+ // touch devices and display, you do not care about what port the touch device
+ // is connected via. All touch devices of the same kind will have the same
+ // calibration data for a given display irrespective of the port they are
+ // connected to.
+ struct WeakComp {
+ bool operator()(const TouchDeviceIdentifier& lhs,
+ const TouchDeviceIdentifier& rhs) const {
+ return lhs.id() < rhs.id();
+ }
+ };
+
// Returns a touch device identifier used as a default or a fallback option.
static const TouchDeviceIdentifier& GetFallbackTouchDeviceIdentifier();
@@ -39,6 +58,7 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceIdentifier {
const ui::TouchscreenDevice& touch_device);
explicit TouchDeviceIdentifier(uint32_t identifier);
+ TouchDeviceIdentifier(uint32_t identifier, uint32_t secondary_id);
TouchDeviceIdentifier(const TouchDeviceIdentifier& other);
~TouchDeviceIdentifier() = default;
@@ -49,12 +69,20 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceIdentifier {
bool operator!=(const TouchDeviceIdentifier& other) const;
std::string ToString() const;
+ std::string SecondaryIdToString() const;
+
+ uint32_t id() const { return id_; }
private:
static uint32_t GenerateIdentifier(std::string name,
uint16_t vendor_id,
uint16_t product_id);
uint32_t id_;
+
+ // Used in case there are multiple devices with the same ID. The secondary id
+ // is generated based on EVIOCGPHYS which is stable across reboot and hotplug.
+ // This is not safe across different ports on the device.
+ uint32_t secondary_id_;
};
// A struct that represents all the data required for touch calibration for the
@@ -100,8 +128,11 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceManager {
};
using AssociationInfoMap = std::map<int64_t, TouchAssociationInfo>;
- using TouchAssociationMap =
- std::map<TouchDeviceIdentifier, AssociationInfoMap>;
+ using TouchAssociationMap = std::map<TouchDeviceIdentifier,
+ AssociationInfoMap,
+ TouchDeviceIdentifier::WeakComp>;
+ using ActiveTouchAssociationMap = std::map<TouchDeviceIdentifier, int64_t>;
+ using PortAssociationMap = ActiveTouchAssociationMap;
TouchDeviceManager();
~TouchDeviceManager();
@@ -158,20 +189,30 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceManager {
std::vector<TouchDeviceIdentifier> GetAssociatedTouchDevicesForDisplay(
int64_t display_id) const;
- // Registers the touch associations retrieved from the persistent store. This
- // function is used to initialize the TouchDeviceManager on system start up.
- void RegisterTouchAssociations(const TouchAssociationMap& touch_associations);
+ // Registers the touch associations and port associations retrieved from the
+ // persistent store. This function is used to initialize the
+ // TouchDeviceManager on system start up.
+ void RegisterTouchAssociations(const TouchAssociationMap& touch_associations,
+ const PortAssociationMap& port_associations);
const TouchAssociationMap& touch_associations() const {
return touch_associations_;
}
+ const PortAssociationMap& port_associations() const {
+ return port_associations_;
+ }
+
private:
friend class test::TouchDeviceManagerTestApi;
void AssociateInternalDevices(std::vector<ManagedDisplayInfo*>* displays,
std::vector<ui::TouchscreenDevice>* devices);
+ void AssociateDevicesWithCollision(
+ std::vector<ManagedDisplayInfo*>* displays,
+ std::vector<ui::TouchscreenDevice>* devices);
+
void AssociateFromHistoricalData(std::vector<ManagedDisplayInfo*>* displays,
std::vector<ui::TouchscreenDevice>* devices);
@@ -197,10 +238,17 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceManager {
// association information for this system.
TouchAssociationMap touch_associations_;
- // A mapping of touch devices identified by their TouchDeviceIdentifier and
- // display ids they are currently associated with. This map only contains
- // items (displays and touch devices) that are currently active.
- std::map<TouchDeviceIdentifier, int64_t> active_touch_associations_;
+ // A mapping of Touch device and the port it is connected via, to the display.
+ // This is used when some touch devices cannot be distinguished from one
+ // another except based on the port they are connected via. We use the
+ // EVIOCGPHYS information of the touch device to get the port information.
+ PortAssociationMap port_associations_;
+
+ // A mapping between touch devices(identified by their TouchDeviceIdentifier)
+ // and display ids of the display that they are currently associated with.
+ // This map only contains items (displays and touch devices) that are
+ // currently active.
+ ActiveTouchAssociationMap active_touch_associations_;
DISALLOW_COPY_AND_ASSIGN(TouchDeviceManager);
};
diff --git a/chromium/ui/display/manager/chromeos/touch_device_manager_unittest.cc b/chromium/ui/display/manager/chromeos/touch_device_manager_unittest.cc
index 472f0bafb2a..fc3d847487b 100644
--- a/chromium/ui/display/manager/chromeos/touch_device_manager_unittest.cc
+++ b/chromium/ui/display/manager/chromeos/touch_device_manager_unittest.cc
@@ -8,7 +8,6 @@
#include <string>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -406,7 +405,8 @@ class TouchAssociationFromPrefTest : public TouchAssociationTest {
touch_associations[TouchDeviceIdentifier::FromDevice(devices_[2])]
[displays_[0].id()] = CreateTouchAssociationInfo(3);
- touch_device_manager_->RegisterTouchAssociations(touch_associations);
+ touch_device_manager_->RegisterTouchAssociations(
+ touch_associations, TouchDeviceManager::PortAssociationMap());
}
void TearDown() override {
@@ -581,4 +581,264 @@ TEST_F(TouchAssociationFromPrefTest, InternalDisplayIsNotMatched) {
EXPECT_TRUE(AreAssociated(displays_[3], devices_[1]));
}
+class TouchAssociationWithDuplicateDeviceTest : public TouchAssociationTest {
+ public:
+ TouchAssociationWithDuplicateDeviceTest() {}
+ ~TouchAssociationWithDuplicateDeviceTest() override {}
+
+ void SetUp() override {
+ TouchAssociationTest::SetUp();
+ TouchDeviceManager::TouchAssociationMap touch_associations;
+ TouchDeviceManager::PortAssociationMap port_associations;
+
+ // Create different ports.
+ const std::vector<std::string> ports = {"port 0", "port 1", "port 2",
+ "port 3", "port 4"};
+
+ std::string device_name_1 = "device 1";
+ std::string device_name_2 = "device 2";
+
+ // Create a device with name |device_name_1| connected to |ports[0]|.
+ devices_.push_back(CreateTouchscreenDevice(
+ 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+ devices_.back().name = device_name_1;
+ devices_.back().phys = ports[0];
+
+ int vendor_id = devices_.back().vendor_id;
+ int product_id = devices_.back().product_id;
+
+ devices_.push_back(CreateTouchscreenDevice(
+ 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+
+ // Create another device with the same name but different port. Ensure that
+ // the touch device idnetifier is the same by setting the same vendor id,
+ // product id and name.
+ devices_.back().name = device_name_1;
+ devices_.back().phys = ports[1];
+ devices_.back().vendor_id = vendor_id;
+ devices_.back().product_id = product_id;
+
+ devices_.push_back(CreateTouchscreenDevice(
+ 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+ devices_.back().name = device_name_1;
+ devices_.back().phys = ports[2];
+ devices_.back().vendor_id = vendor_id;
+ devices_.back().product_id = product_id;
+
+ devices_.push_back(CreateTouchscreenDevice(
+ 4, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(800, 600)));
+
+ devices_.push_back(CreateTouchscreenDevice(
+ 5, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096)));
+ devices_.back().name = device_name_2;
+ devices_.back().phys = ports[3];
+
+ vendor_id = devices_.back().vendor_id;
+ product_id = devices_.back().product_id;
+
+ devices_.push_back(CreateTouchscreenDevice(
+ 6, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096)));
+ devices_.back().name = device_name_2;
+ devices_.back().phys = ports[4];
+ devices_.back().vendor_id = vendor_id;
+ devices_.back().product_id = product_id;
+
+ // Create priority list for Device Id = 1
+ // - Display Index 0
+ // - Display Index 2
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[0])] =
+ TouchDeviceManager::AssociationInfoMap();
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[0])]
+ [displays_[0].id()] = CreateTouchAssociationInfo(1);
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[0])]
+ [displays_[2].id()] = CreateTouchAssociationInfo(2);
+
+ // Create priority list for Device Id = 2
+ // - Display Index 3
+ // - Display Index 1
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[1])] =
+ TouchDeviceManager::AssociationInfoMap();
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[1])]
+ [displays_[3].id()] = CreateTouchAssociationInfo(1);
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[1])]
+ [displays_[1].id()] = CreateTouchAssociationInfo(2);
+
+ // Craete priority list for Device Id = 3
+ // - Display Index 2
+ // - Display Index 3
+ // - Display Index 0
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[2])] =
+ TouchDeviceManager::AssociationInfoMap();
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[2])]
+ [displays_[2].id()] = CreateTouchAssociationInfo(1);
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[2])]
+ [displays_[3].id()] = CreateTouchAssociationInfo(2);
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[2])]
+ [displays_[0].id()] = CreateTouchAssociationInfo(3);
+
+ // Craete priority list for Device Id = 5
+ // - Display Index 3
+ // - Display Index 2
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[4])] =
+ TouchDeviceManager::AssociationInfoMap();
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[4])]
+ [displays_[3].id()] = CreateTouchAssociationInfo(1);
+ touch_associations[TouchDeviceIdentifier::FromDevice(devices_[4])]
+ [displays_[2].id()] = CreateTouchAssociationInfo(2);
+
+ // Map ports:
+ // - { Touch Device 1, ports[0] } -> Display Index 2
+ // - { Touch Device 2, ports[1] } -> Display Index 3
+ // - { Touch Device 3, ports[2] } -> Display Index 2
+ // - { Touch Device 5, ports[4] } -> Display Index 0
+ port_associations[TouchDeviceIdentifier::FromDevice(devices_[0])] =
+ displays_[2].id();
+ port_associations[TouchDeviceIdentifier::FromDevice(devices_[1])] =
+ displays_[3].id();
+ port_associations[TouchDeviceIdentifier::FromDevice(devices_[2])] =
+ displays_[2].id();
+ port_associations[TouchDeviceIdentifier::FromDevice(devices_[4])] =
+ displays_[0].id();
+
+ touch_device_manager_->RegisterTouchAssociations(touch_associations,
+ port_associations);
+ }
+
+ void TearDown() override {
+ TouchAssociationTest::TearDown();
+ devices_.clear();
+ }
+
+ protected:
+ std::vector<ui::TouchscreenDevice> devices_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TouchAssociationWithDuplicateDeviceTest);
+};
+
+TEST_F(TouchAssociationWithDuplicateDeviceTest, CorrectMapping) {
+ test::ScopedSetInternalDisplayId set_internal(display_manager(),
+ displays_[1].id());
+
+ touch_device_manager()->AssociateTouchscreens(&displays_, devices_);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[0]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[0], devices_[4]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[1]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[1], devices_[3]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[2]), 2u);
+ EXPECT_TRUE(AreAssociated(displays_[2], devices_[0]));
+ EXPECT_TRUE(AreAssociated(displays_[2], devices_[2]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[3]), 2u);
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[1]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[5]));
+}
+
+TEST_F(TouchAssociationWithDuplicateDeviceTest, NoDuplicateIds) {
+ test::ScopedSetInternalDisplayId set_internal(display_manager(),
+ displays_[1].id());
+
+ std::vector<ui::TouchscreenDevice> devices;
+ devices.push_back(devices_[1]);
+ devices.push_back(devices_[3]);
+ devices.push_back(devices_[4]);
+
+ touch_device_manager()->AssociateTouchscreens(&displays_, devices);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[0]), 0u);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[1]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[1], devices_[3]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[2]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[2], devices_[1]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[3]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[4]));
+}
+
+TEST_F(TouchAssociationWithDuplicateDeviceTest, CorrectMappingWithSomeMissing) {
+ test::ScopedSetInternalDisplayId set_internal(display_manager(),
+ displays_[1].id());
+ DisplayInfoList displays;
+ displays.push_back(displays_[0]);
+ displays.push_back(displays_[1]);
+ displays.push_back(displays_[3]);
+
+ touch_device_manager()->AssociateTouchscreens(&displays, devices_);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[0]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[0], devices_[4]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[1]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[1], devices_[3]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[3]), 4u);
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[0]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[1]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[2]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[5]));
+}
+
+TEST_F(TouchAssociationWithDuplicateDeviceTest, UpdatePortBeforeAssociation) {
+ test::ScopedSetInternalDisplayId set_internal(display_manager(),
+ displays_[1].id());
+
+ // Reassociate display at index 3 to touch device at index 2. This will
+ // bring the display to the top of the priority list and map the port the
+ // device is connected to, to display 3.
+ touch_device_manager()->AddTouchCalibrationData(
+ TouchDeviceIdentifier::FromDevice(devices_[2]), displays_[3].id(),
+ TouchCalibrationData());
+
+ touch_device_manager()->AssociateTouchscreens(&displays_, devices_);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[0]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[0], devices_[4]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[1]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[1], devices_[3]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[2]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[2], devices_[0]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[3]), 3u);
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[1]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[2]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[5]));
+}
+
+TEST_F(TouchAssociationWithDuplicateDeviceTest, ChangeAssociation) {
+ test::ScopedSetInternalDisplayId set_internal(display_manager(),
+ displays_[1].id());
+
+ touch_device_manager()->AssociateTouchscreens(&displays_, devices_);
+
+ // Reassociate display at index 3 to touch device at index 2. This will
+ // bring the display to the top of the priority list and map the port the
+ // device is connected to, to display 3.
+ touch_device_manager()->AddTouchCalibrationData(
+ TouchDeviceIdentifier::FromDevice(devices_[2]), displays_[3].id(),
+ TouchCalibrationData());
+
+ touch_device_manager()->AssociateTouchscreens(&displays_, devices_);
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[0]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[0], devices_[4]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[1]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[1], devices_[3]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[2]), 1u);
+ EXPECT_TRUE(AreAssociated(displays_[2], devices_[0]));
+
+ EXPECT_EQ(GetTouchDeviceCount(displays_[3]), 3u);
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[1]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[2]));
+ EXPECT_TRUE(AreAssociated(displays_[3], devices_[5]));
+}
+
} // namespace display
diff --git a/chromium/ui/display/manager/chromeos/touch_transform_controller_unittest.cc b/chromium/ui/display/manager/chromeos/touch_transform_controller_unittest.cc
index a9107fdb35a..35b769b93f4 100644
--- a/chromium/ui/display/manager/chromeos/touch_transform_controller_unittest.cc
+++ b/chromium/ui/display/manager/chromeos/touch_transform_controller_unittest.cc
@@ -8,7 +8,6 @@
#include <string>
#include <utility>
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/manager/chromeos/default_touch_transform_setter.h"
diff --git a/chromium/ui/display/manager/chromeos/update_display_configuration_task_unittest.cc b/chromium/ui/display/manager/chromeos/update_display_configuration_task_unittest.cc
index c1dcc99cf8c..526d70e4e8d 100644
--- a/chromium/ui/display/manager/chromeos/update_display_configuration_task_unittest.cc
+++ b/chromium/ui/display/manager/chromeos/update_display_configuration_task_unittest.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/display/manager/display_manager.cc b/chromium/ui/display/manager/display_manager.cc
index e7fd443794b..d587d229537 100644
--- a/chromium/ui/display/manager/display_manager.cc
+++ b/chromium/ui/display/manager/display_manager.cc
@@ -17,7 +17,6 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
@@ -42,6 +41,7 @@
#if defined(OS_CHROMEOS)
#include "base/sys_info.h"
#include "chromeos/system/devicemode.h"
+#include "ui/display/manager/chromeos/display_util.h"
#endif
#if defined(OS_WIN)
@@ -602,6 +602,10 @@ bool DisplayManager::SetDisplayMode(int64_t display_id,
// continue to fill |display_info_list|, since we won't be
// synchronously updating the displays here.
resolution_changed = true;
+
+ // Different resolutions allow different zoom factors to be set in the
+ // UI. To avoid confusion in the UI, reset the zoom factor to 1.0.
+ display_info_[display_id].set_zoom_factor(1.f);
break;
}
if (info.device_scale_factor() != display_mode.device_scale_factor()) {
@@ -651,11 +655,12 @@ void DisplayManager::RegisterDisplayProperty(
Display::RotationSource::USER);
display_info_[display_id].SetRotation(rotation,
Display::RotationSource::ACTIVE);
- // Just in case the preference file was corrupted.
- // TODO(mukai): register |display_modes_| here as well, so the lookup for the
- // default mode in GetActiveModeForDisplayId() gets much simpler.
- if (0.5f <= ui_scale && ui_scale <= 2.0f)
+
+ if (features::IsDisplayZoomSettingEnabled())
+ display_info_[display_id].set_zoom_factor(display_zoom_factor);
+ else if (0.5f <= ui_scale && ui_scale <= 2.0f)
display_info_[display_id].set_configured_ui_scale(ui_scale);
+
if (overscan_insets)
display_info_[display_id].SetOverscanInsets(*overscan_insets);
@@ -667,8 +672,6 @@ void DisplayManager::RegisterDisplayProperty(
device_scale_factor);
display_modes_[display_id] = mode;
}
-
- display_zoom_factors_[display_id] = display_zoom_factor;
}
bool DisplayManager::GetActiveModeForDisplayId(int64_t display_id,
@@ -690,7 +693,8 @@ bool DisplayManager::GetActiveModeForDisplayId(int64_t display_id,
for (const auto& display_mode : display_modes) {
if (GetDisplayIdForUIScaling() == display_id) {
- if (info.configured_ui_scale() == display_mode.ui_scale()) {
+ if (info.configured_ui_scale() == display_mode.ui_scale() ||
+ display_modes.size() == 1) {
*mode = display_mode;
return true;
}
@@ -1487,8 +1491,11 @@ void DisplayManager::ClearTouchCalibrationData(
void DisplayManager::UpdateZoomFactor(int64_t display_id, float zoom_factor) {
DCHECK(zoom_factor > 0);
DCHECK_NE(display_id, kInvalidDisplayId);
+ auto iter = display_info_.find(display_id);
+ if (iter == display_info_.end())
+ return;
- display_zoom_factors_[display_id] = zoom_factor;
+ iter->second.set_zoom_factor(zoom_factor);
for (const auto& display : active_display_list_) {
if (display.id() == display_id) {
@@ -1499,14 +1506,6 @@ void DisplayManager::UpdateZoomFactor(int64_t display_id, float zoom_factor) {
}
#endif
-float DisplayManager::GetZoomFactorForDisplay(int64_t display_id) const {
- // If there is no entry for the given display id, then the zoom factor is
- // still at its default level of 100% zoom.
- if (!base::ContainsKey(display_zoom_factors_, display_id))
- return 1.f;
- return display_zoom_factors_.at(display_id);
-}
-
void DisplayManager::SetDefaultMultiDisplayModeForCurrentDisplays(
MultiDisplayMode mode) {
DCHECK_NE(MIRRORING, mode);
@@ -1572,8 +1571,8 @@ void DisplayManager::CreateMirrorWindowAsyncIfAny() {
if (software_mirroring_display_list_.empty() || !delegate_)
return;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
- weak_ptr_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&DisplayManager::CreateMirrorWindowIfAny,
+ weak_ptr_factory_.GetWeakPtr()));
}
void DisplayManager::UpdateInternalManagedDisplayModeListForTest() {
@@ -1585,6 +1584,7 @@ void DisplayManager::UpdateInternalManagedDisplayModeListForTest() {
SetInternalManagedDisplayModeList(info);
}
+// TODO(malaykeshav): Make this work with display zoom.
bool DisplayManager::ZoomInternalDisplay(bool up) {
int64_t display_id =
IsInUnifiedMode() ? kUnifiedDisplayId : GetDisplayIdForUIScaling();
@@ -1605,6 +1605,56 @@ bool DisplayManager::ZoomInternalDisplay(bool up) {
return result ? SetDisplayMode(display_id, mode) : false;
}
+bool DisplayManager::ZoomDisplay(int64_t display_id, bool up) {
+#if defined(OS_CHROMEOS)
+ DCHECK(!IsInUnifiedMode());
+ ManagedDisplayMode display_mode;
+ if (!GetActiveModeForDisplayId(display_id, &display_mode))
+ return false;
+ const std::vector<double> zooms = GetDisplayZoomFactors(display_mode);
+ auto iter = display_info_.find(display_id);
+ if (iter == display_info_.end())
+ return false;
+
+ const double current_display_zoom = iter->second.zoom_factor();
+
+ // Find the index of |current_display_zoom| in |zooms|. The nearest value is
+ // used if the exact match is not found.
+ std::size_t zoom_idx = 0;
+ double min_diff = std::abs(zooms[zoom_idx] - current_display_zoom);
+ for (std::size_t i = 1; i < zooms.size(); i++) {
+ if (std::abs(current_display_zoom - zooms[i]) < min_diff) {
+ min_diff = std::abs(current_display_zoom - zooms[i]);
+ zoom_idx = i;
+ }
+ }
+ // The index of the next zoom value.
+ const std::size_t next_zoom_idx = zoom_idx + (up ? -1 : 1);
+
+ // If the zoom index is out of bounds, that is, the display is already at
+ // maximum or minimum zoom then do nothing.
+ if (next_zoom_idx < 0 || next_zoom_idx >= zooms.size())
+ return false;
+
+ iter->second.set_zoom_factor(zooms[next_zoom_idx]);
+ UpdateDisplays();
+ return true;
+#else
+ return false;
+#endif // (OS_CHROMEOS)
+}
+
+void DisplayManager::ResetDisplayZoom(int64_t display_id) {
+ DCHECK(!IsInUnifiedMode());
+ auto iter = display_info_.find(display_id);
+ if (iter == display_info_.end())
+ return;
+ if (std::abs(iter->second.zoom_factor() - 1.f) > 0.001) {
+ iter->second.set_zoom_factor(1.f);
+ UpdateDisplays();
+ }
+}
+
bool DisplayManager::ResetDisplayToDefaultMode(int64_t id) {
if (!IsActiveDisplayId(id) || !Display::IsInternalDisplayId(id))
return false;
@@ -1971,9 +2021,6 @@ Display DisplayManager::CreateDisplayFromDisplayInfoById(int64_t id) {
gfx::Rect bounds_in_native(display_info.size_in_pixel());
float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
- // Apply the zoom factor for the display.
- device_scale_factor *= GetZoomFactorForDisplay(id);
-
// Simply set the origin to (0,0). The primary display's origin is
// always (0,0) and the bounds of non-primary display(s) will be updated
// in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
diff --git a/chromium/ui/display/manager/display_manager.h b/chromium/ui/display/manager/display_manager.h
index 2ff69b5e70c..6de527a6c4f 100644
--- a/chromium/ui/display/manager/display_manager.h
+++ b/chromium/ui/display/manager/display_manager.h
@@ -445,8 +445,6 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
base::Optional<TouchDeviceIdentifier> touch_device_identifier);
void UpdateZoomFactor(int64_t display_id, float zoom_factor);
#endif
- // Returns the zoom foactor for the display identified by |display_id|.
- float GetZoomFactorForDisplay(int64_t display_id) const;
// Sets/gets default multi display mode.
void SetDefaultMultiDisplayModeForCurrentDisplays(MultiDisplayMode mode);
@@ -476,9 +474,17 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// Zoom the internal display.
bool ZoomInternalDisplay(bool up);
+ // Zooms the display identified by |display_id| by increasing or decreasing
+ // its zoom factor value by 1 unit. Zooming in will have no effect on the
+ // display if it is already at its maximum zoom. Vice versa for zooming out.
+ bool ZoomDisplay(int64_t display_id, bool up);
+
// Reset the internal display zoom.
void ResetInternalDisplayZoom();
+ // Resets the zoom value to 1 for the display identified by |display_id|.
+ void ResetDisplayZoom(int64_t display_id);
+
// Notifies observers of display configuration changes.
void NotifyMetricsChanged(const Display& display, uint32_t metrics);
void NotifyDisplayAdded(const Display& display);
@@ -609,9 +615,6 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// Selected display modes for displays. Key is the displays' ID.
std::map<int64_t, ManagedDisplayMode> display_modes_;
- // Zoom level for each display.
- std::map<int64_t, float> display_zoom_factors_;
-
// When set to true, the host window's resize event updates the display's
// size. This is set to true when running on desktop environment (for
// debugging) so that resizing the host window will update the display
diff --git a/chromium/ui/display/manager/display_pref_util.h b/chromium/ui/display/manager/display_pref_util.h
deleted file mode 100644
index dea15cface2..00000000000
--- a/chromium/ui/display/manager/display_pref_util.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_DISPLAY_MANAGER_DISPLAY_PREF_UTIL_H
-#define UI_DISPLAY_MANAGER_DISPLAY_PREF_UTIL_H
-
-#include <map>
-#include <string>
-
-#include "base/strings/string_piece.h"
-
-namespace display {
-
-// Utility templates to create enum to string map and
-// a function to find an enum value from a string.
-template <typename T>
-std::map<T, std::string>* CreateToStringMap(T k1,
- const std::string& v1,
- T k2,
- const std::string& v2,
- T k3,
- const std::string& v3,
- T k4,
- const std::string& v4) {
- std::map<T, std::string>* map = new std::map<T, std::string>();
- (*map)[k1] = v1;
- (*map)[k2] = v2;
- (*map)[k3] = v3;
- (*map)[k4] = v4;
- return map;
-}
-
-template <typename T>
-std::map<T, std::string>* CreateToStringMap(T k1,
- const std::string& v1,
- T k2,
- const std::string& v2,
- T k3,
- const std::string& v3) {
- std::map<T, std::string>* map = new std::map<T, std::string>();
- (*map)[k1] = v1;
- (*map)[k2] = v2;
- (*map)[k3] = v3;
- return map;
-}
-
-template <typename T>
-bool ReverseFind(const std::map<T, std::string>* map,
- const base::StringPiece& value,
- T* key) {
- typename std::map<T, std::string>::const_iterator iter = map->begin();
- for (; iter != map->end(); ++iter) {
- if (iter->second == value) {
- *key = iter->first;
- return true;
- }
- }
- return false;
-}
-
-} // namespace display
-
-#endif // UI_DISPLAY_MANAGER_DISPLAY_PREF_UTIL_H
diff --git a/chromium/ui/display/manager/fake_display_delegate.cc b/chromium/ui/display/manager/fake_display_delegate.cc
index 8d47679bb2f..c03a926ce20 100644
--- a/chromium/ui/display/manager/fake_display_delegate.cc
+++ b/chromium/ui/display/manager/fake_display_delegate.cc
@@ -10,7 +10,6 @@
#include "base/command_line.h"
#include "base/hash.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
diff --git a/chromium/ui/display/manager/fake_display_snapshot.cc b/chromium/ui/display/manager/fake_display_snapshot.cc
index 3db0e2c84f1..9bdbd1dedd7 100644
--- a/chromium/ui/display/manager/fake_display_snapshot.cc
+++ b/chromium/ui/display/manager/fake_display_snapshot.cc
@@ -9,7 +9,6 @@
#include <utility>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
@@ -163,7 +162,7 @@ std::unique_ptr<FakeDisplaySnapshot> Builder::Build() {
return std::make_unique<FakeDisplaySnapshot>(
id_, origin_, physical_size, type_, is_aspect_preserving_scaling_,
has_overscan_, has_color_correction_matrix_, name_, std::move(modes_),
- current_mode_, native_mode_, product_id_, maximum_cursor_size_);
+ current_mode_, native_mode_, product_code_, maximum_cursor_size_);
}
Builder& Builder::SetId(int64_t id) {
@@ -231,8 +230,8 @@ Builder& Builder::SetName(const std::string& name) {
return *this;
}
-Builder& Builder::SetProductId(int64_t product_id) {
- product_id_ = product_id;
+Builder& Builder::SetProductCode(int64_t product_code) {
+ product_code_ = product_code;
return *this;
}
@@ -291,7 +290,7 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(int64_t display_id,
DisplayModeList modes,
const DisplayMode* current_mode,
const DisplayMode* native_mode,
- int64_t product_id,
+ int64_t product_code,
const gfx::Size& maximum_cursor_size)
: DisplaySnapshot(display_id,
origin,
@@ -307,7 +306,8 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(int64_t display_id,
std::vector<uint8_t>(),
current_mode,
native_mode,
- product_id,
+ product_code,
+ 2018 /*year_of_manufacture */,
maximum_cursor_size) {}
FakeDisplaySnapshot::~FakeDisplaySnapshot() {}
diff --git a/chromium/ui/display/manager/fake_display_snapshot.h b/chromium/ui/display/manager/fake_display_snapshot.h
index d47abe1343c..8df35ccc3b7 100644
--- a/chromium/ui/display/manager/fake_display_snapshot.h
+++ b/chromium/ui/display/manager/fake_display_snapshot.h
@@ -59,7 +59,7 @@ class DISPLAY_MANAGER_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
Builder& SetHasOverscan(bool has_overscan);
Builder& SetHasColorCorrectionMatrix(bool val);
Builder& SetName(const std::string& name);
- Builder& SetProductId(int64_t product_id);
+ Builder& SetProductCode(int64_t product_code);
Builder& SetMaximumCursorSize(const gfx::Size& maximum_cursor_size);
// Sets physical_size so that the screen has the specified DPI using the
// native resolution.
@@ -85,7 +85,7 @@ class DISPLAY_MANAGER_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
bool has_overscan_ = false;
bool has_color_correction_matrix_ = false;
std::string name_;
- int64_t product_id_ = DisplaySnapshot::kInvalidProductID;
+ int64_t product_code_ = DisplaySnapshot::kInvalidProductCode;
gfx::Size maximum_cursor_size_ = gfx::Size(64, 64);
DisplayModeList modes_;
const DisplayMode* current_mode_ = nullptr;
@@ -105,7 +105,7 @@ class DISPLAY_MANAGER_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
DisplayModeList modes,
const DisplayMode* current_mode,
const DisplayMode* native_mode,
- int64_t product_id,
+ int64_t product_code,
const gfx::Size& maximum_cursor_size);
~FakeDisplaySnapshot() override;
diff --git a/chromium/ui/display/manager/json_converter.cc b/chromium/ui/display/manager/json_converter.cc
index 1d4c0a4bb32..363c2da130c 100644
--- a/chromium/ui/display/manager/json_converter.cc
+++ b/chromium/ui/display/manager/json_converter.cc
@@ -11,7 +11,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "ui/display/display_layout.h"
-#include "ui/display/manager/display_pref_util.h"
namespace display {
diff --git a/chromium/ui/display/manager/managed_display_info.cc b/chromium/ui/display/manager/managed_display_info.cc
index c4906316e61..ff3c119c93a 100644
--- a/chromium/ui/display/manager/managed_display_info.cc
+++ b/chromium/ui/display/manager/managed_display_info.cc
@@ -260,12 +260,14 @@ ManagedDisplayInfo ManagedDisplayInfo::CreateFromSpecWithID(
ManagedDisplayInfo::ManagedDisplayInfo()
: id_(kInvalidDisplayId),
+ year_of_manufacture_(kInvalidYearOfManufacture),
has_overscan_(false),
active_rotation_source_(Display::RotationSource::UNKNOWN),
touch_support_(Display::TouchSupport::UNKNOWN),
device_scale_factor_(1.0f),
device_dpi_(kDpi96),
overscan_insets_in_dip_(0, 0, 0, 0),
+ zoom_factor_(1.f),
configured_ui_scale_(1.0f),
native_(false),
is_aspect_preserving_scaling_(false),
@@ -276,12 +278,14 @@ ManagedDisplayInfo::ManagedDisplayInfo(int64_t id,
bool has_overscan)
: id_(id),
name_(name),
+ year_of_manufacture_(kInvalidYearOfManufacture),
has_overscan_(has_overscan),
active_rotation_source_(Display::RotationSource::UNKNOWN),
touch_support_(Display::TouchSupport::UNKNOWN),
device_scale_factor_(1.0f),
device_dpi_(kDpi96),
overscan_insets_in_dip_(0, 0, 0, 0),
+ zoom_factor_(1.f),
configured_ui_scale_(1.0f),
native_(false),
is_aspect_preserving_scaling_(false),
@@ -312,6 +316,9 @@ Display::Rotation ManagedDisplayInfo::GetRotation(
void ManagedDisplayInfo::Copy(const ManagedDisplayInfo& native_info) {
DCHECK(id_ == native_info.id_);
+ manufacturer_id_ = native_info.manufacturer_id_;
+ product_id_ = native_info.product_id_;
+ year_of_manufacture_ = native_info.year_of_manufacture_;
name_ = native_info.name_;
has_overscan_ = native_info.has_overscan_;
@@ -340,6 +347,7 @@ void ManagedDisplayInfo::Copy(const ManagedDisplayInfo& native_info) {
overscan_insets_in_dip_ = native_info.overscan_insets_in_dip_;
rotations_ = native_info.rotations_;
+ zoom_factor_ = native_info.zoom_factor_;
configured_ui_scale_ = native_info.configured_ui_scale_;
}
@@ -357,10 +365,10 @@ float ManagedDisplayInfo::GetDensityRatio() const {
float ManagedDisplayInfo::GetEffectiveDeviceScaleFactor() const {
if (Display::IsInternalDisplayId(id_) && device_scale_factor_ == 1.25f)
- return (configured_ui_scale_ == 0.8f) ? 1.25f : 1.0f;
+ return ((configured_ui_scale_ == 0.8f) ? 1.25f : 1.0f) * zoom_factor_;
if (device_scale_factor_ == configured_ui_scale_)
- return 1.0f;
- return device_scale_factor_;
+ return zoom_factor_;
+ return device_scale_factor_ * zoom_factor_;
}
float ManagedDisplayInfo::GetEffectiveUIScale() const {
@@ -395,7 +403,7 @@ void ManagedDisplayInfo::SetOverscanInsets(const gfx::Insets& insets_in_dip) {
}
gfx::Insets ManagedDisplayInfo::GetOverscanInsetsInPixel() const {
- return overscan_insets_in_dip_.Scale(device_scale_factor_);
+ return overscan_insets_in_dip_.Scale(device_scale_factor_ * zoom_factor_);
}
void ManagedDisplayInfo::SetManagedDisplayModes(
@@ -418,9 +426,9 @@ std::string ManagedDisplayInfo::ToString() const {
std::string result = base::StringPrintf(
"ManagedDisplayInfo[%lld] native bounds=%s, size=%s, device-scale=%g, "
- "overscan=%s, rotation=%d, ui-scale=%g, touchscreen=%s, ",
+ "display-zoom=%g, overscan=%s, rotation=%d, ui-scale=%g, touchscreen=%s",
static_cast<long long int>(id_), bounds_in_native_.ToString().c_str(),
- size_in_pixel_.ToString().c_str(), device_scale_factor_,
+ size_in_pixel_.ToString().c_str(), device_scale_factor_, zoom_factor_,
overscan_insets_in_dip_.ToString().c_str(), rotation_degree,
configured_ui_scale_,
touch_support_ == Display::TouchSupport::AVAILABLE
diff --git a/chromium/ui/display/manager/managed_display_info.h b/chromium/ui/display/manager/managed_display_info.h
index 3f25ae1f5a7..f09dd597d89 100644
--- a/chromium/ui/display/manager/managed_display_info.h
+++ b/chromium/ui/display/manager/managed_display_info.h
@@ -147,6 +147,9 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
float device_scale_factor() const { return device_scale_factor_; }
void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
+ float zoom_factor() const { return zoom_factor_; }
+ void set_zoom_factor(float zoom_factor) { zoom_factor_ = zoom_factor; }
+
// Gets/Sets the device DPI of the display.
float device_dpi() const { return device_dpi_; }
void set_device_dpi(float dpi) { device_dpi_ = dpi; }
@@ -253,6 +256,15 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
maximum_cursor_size_ = size;
}
+ const std::string& manufacturer_id() const { return manufacturer_id_; }
+ void set_manufacturer_id(const std::string& id) { manufacturer_id_ = id; }
+
+ const std::string& product_id() const { return product_id_; }
+ void set_product_id(const std::string& id) { product_id_ = id; }
+
+ int32_t year_of_manufacture() const { return year_of_manufacture_; }
+ void set_year_of_manufacture(int32_t year) { year_of_manufacture_ = year; }
+
// Returns a string representation of the ManagedDisplayInfo, excluding
// display modes.
std::string ToString() const;
@@ -264,6 +276,9 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
private:
int64_t id_;
std::string name_;
+ std::string manufacturer_id_;
+ std::string product_id_;
+ int32_t year_of_manufacture_;
base::FilePath sys_path_;
bool has_overscan_;
std::map<Display::RotationSource, Display::Rotation> rotations_;
@@ -285,6 +300,11 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
gfx::Size size_in_pixel_;
gfx::Insets overscan_insets_in_dip_;
+ // The zoom level currently applied to the display. This value is appended
+ // multiplicatively to the device scale factor to get the effecting scaling
+ // for a display.
+ float zoom_factor_;
+
// The pixel scale of the display. This is used to simply expand (or shrink)
// the desktop over the native display resolution (useful in HighDPI display).
// Note that this should not be confused with the device scale factor, which
diff --git a/chromium/ui/display/mojo/BUILD.gn b/chromium/ui/display/mojo/BUILD.gn
index b38524e92bc..854ee9352ff 100644
--- a/chromium/ui/display/mojo/BUILD.gn
+++ b/chromium/ui/display/mojo/BUILD.gn
@@ -17,7 +17,7 @@ mojom("interfaces") {
]
public_deps = [
- "//mojo/common:common_custom_types",
+ "//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
"//ui/gfx/mojo",
]
diff --git a/chromium/ui/display/mojo/display_snapshot.mojom b/chromium/ui/display/mojo/display_snapshot.mojom
index 8f52fe50661..fd6a818c5a0 100644
--- a/chromium/ui/display/mojo/display_snapshot.mojom
+++ b/chromium/ui/display/mojo/display_snapshot.mojom
@@ -4,7 +4,7 @@
module display.mojom;
-import "mojo/common/file_path.mojom";
+import "mojo/public/mojom/base/file_path.mojom";
import "ui/display/mojo/display_constants.mojom";
import "ui/display/mojo/display_mode.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -21,13 +21,15 @@ struct DisplaySnapshot {
bool has_color_correction_matrix;
gfx.mojom.ColorSpace color_space;
string display_name;
- mojo.common.mojom.FilePath sys_path;
+ mojo_base.mojom.FilePath sys_path;
array<display.mojom.DisplayMode> modes;
array<uint8> edid;
uint64 current_mode_index;
bool has_current_mode;
uint64 native_mode_index;
bool has_native_mode;
- int64 product_id;
+ // |product_code| is a combination of the manufacturer id and the product id.
+ int64 product_code;
+ int32 year_of_manufacture;
gfx.mojom.Size maximum_cursor_size;
};
diff --git a/chromium/ui/display/mojo/display_snapshot_struct_traits.cc b/chromium/ui/display/mojo/display_snapshot_struct_traits.cc
index 85f507180c1..165c378e65b 100644
--- a/chromium/ui/display/mojo/display_snapshot_struct_traits.cc
+++ b/chromium/ui/display/mojo/display_snapshot_struct_traits.cc
@@ -132,7 +132,7 @@ bool StructTraits<display::mojom::DisplaySnapshotDataView,
data.is_aspect_preserving_scaling(), data.has_overscan(),
data.has_color_correction_matrix(), color_space, display_name, file_path,
std::move(modes), std::move(edid), current_mode, native_mode,
- data.product_id(), maximum_cursor_size);
+ data.product_code(), data.year_of_manufacture(), maximum_cursor_size);
return true;
}
diff --git a/chromium/ui/display/mojo/display_snapshot_struct_traits.h b/chromium/ui/display/mojo/display_snapshot_struct_traits.h
index 2be5ea00591..e80a273966e 100644
--- a/chromium/ui/display/mojo/display_snapshot_struct_traits.h
+++ b/chromium/ui/display/mojo/display_snapshot_struct_traits.h
@@ -93,9 +93,14 @@ struct StructTraits<display::mojom::DisplaySnapshotDataView,
return snapshot->native_mode() != nullptr;
}
- static int64_t product_id(
+ static int64_t product_code(
const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
- return snapshot->product_id();
+ return snapshot->product_code();
+ }
+
+ static int32_t year_of_manufacture(
+ const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
+ return snapshot->year_of_manufacture();
}
static const gfx::Size& maximum_cursor_size(
diff --git a/chromium/ui/display/mojo/display_struct_traits_unittest.cc b/chromium/ui/display/mojo/display_struct_traits_unittest.cc
index 1dd6cf72c8a..8d956238730 100644
--- a/chromium/ui/display/mojo/display_struct_traits_unittest.cc
+++ b/chromium/ui/display/mojo/display_struct_traits_unittest.cc
@@ -83,7 +83,7 @@ void CheckDisplaySnapShotMojoEqual(const DisplaySnapshot& input,
output.has_color_correction_matrix());
EXPECT_EQ(input.display_name(), output.display_name());
EXPECT_EQ(input.sys_path(), output.sys_path());
- EXPECT_EQ(input.product_id(), output.product_id());
+ EXPECT_EQ(input.product_code(), output.product_code());
EXPECT_EQ(input.modes().size(), output.modes().size());
for (size_t i = 0; i < input.modes().size(); i++)
@@ -252,7 +252,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentAndNativeModesNull) {
const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateREC709();
const std::string display_name("whatever display_name");
const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("a/cb");
- const int64_t product_id = 19;
+ const int64_t product_code = 19;
+ const int32_t year_of_manufacture = 1776;
const DisplayMode display_mode(gfx::Size(13, 11), true, 40.0f);
@@ -267,7 +268,7 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentAndNativeModesNull) {
display_id, origin, physical_size, type, is_aspect_preserving_scaling,
has_overscan, has_color_correction_matrix, display_color_space,
display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
- product_id, maximum_cursor_size);
+ product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -289,7 +290,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentModeNull) {
const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateREC709();
const std::string display_name("whatever display_name");
const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("z/b");
- const int64_t product_id = 9;
+ const int64_t product_code = 9;
+ const int32_t year_of_manufacture = 1776;
const DisplayMode display_mode(gfx::Size(13, 11), true, 50.0f);
@@ -304,7 +306,7 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentModeNull) {
display_id, origin, physical_size, type, is_aspect_preserving_scaling,
has_overscan, has_color_correction_matrix, display_color_space,
display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
- product_id, maximum_cursor_size);
+ product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -326,7 +328,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotExternal) {
const std::string display_name("HP Z24i");
const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateSRGB();
const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("a/cb");
- const int64_t product_id = 139;
+ const int64_t product_code = 139;
+ const int32_t year_of_manufacture = 2018;
const DisplayMode display_mode(gfx::Size(1024, 768), false, 60.0f);
const DisplayMode display_current_mode(gfx::Size(1440, 900), false, 59.89f);
@@ -345,7 +348,7 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotExternal) {
display_id, origin, physical_size, type, is_aspect_preserving_scaling,
has_overscan, has_color_correction_matrix, display_color_space,
display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
- product_id, maximum_cursor_size);
+ product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -367,7 +370,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotInternal) {
gfx::ColorSpace::CreateDisplayP3D65();
const std::string display_name("");
const base::FilePath sys_path;
- const int64_t product_id = 139;
+ const int64_t product_code = 139;
+ const int32_t year_of_manufacture = 2018;
const DisplayMode display_mode(gfx::Size(2560, 1700), false, 95.96f);
@@ -382,7 +386,7 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotInternal) {
display_id, origin, physical_size, type, is_aspect_preserving_scaling,
has_overscan, has_color_correction_matrix, display_color_space,
display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
- product_id, maximum_cursor_size);
+ 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/types/display_constants.h b/chromium/ui/display/types/display_constants.h
index 7ef274f07b6..75baacb357e 100644
--- a/chromium/ui/display/types/display_constants.h
+++ b/chromium/ui/display/types/display_constants.h
@@ -16,6 +16,9 @@ constexpr int64_t kInvalidDisplayId = -1;
// Display ID for a virtual display assigned to a unified desktop.
constexpr int64_t kUnifiedDisplayId = -10;
+// Invalid year of manufacture of the display.
+constexpr int32_t kInvalidYearOfManufacture = -1;
+
// Used to describe the state of a multi-display configuration.
enum MultipleDisplayState {
MULTIPLE_DISPLAY_STATE_INVALID,
diff --git a/chromium/ui/display/types/display_snapshot.cc b/chromium/ui/display/types/display_snapshot.cc
index 1d919340029..b8586ffae36 100644
--- a/chromium/ui/display/types/display_snapshot.cc
+++ b/chromium/ui/display/types/display_snapshot.cc
@@ -74,7 +74,8 @@ DisplaySnapshot::DisplaySnapshot(int64_t display_id,
const std::vector<uint8_t>& edid,
const DisplayMode* current_mode,
const DisplayMode* native_mode,
- int64_t product_id,
+ int64_t product_code,
+ int32_t year_of_manufacture,
const gfx::Size& maximum_cursor_size)
: display_id_(display_id),
origin_(origin),
@@ -90,7 +91,8 @@ DisplaySnapshot::DisplaySnapshot(int64_t display_id,
edid_(edid),
current_mode_(current_mode),
native_mode_(native_mode),
- product_id_(product_id),
+ product_code_(product_code),
+ year_of_manufacture_(year_of_manufacture),
maximum_cursor_size_(maximum_cursor_size) {
// We must explicitly clear out the bytes that represent the serial number.
const size_t end =
@@ -122,25 +124,26 @@ std::unique_ptr<DisplaySnapshot> DisplaySnapshot::Clone() {
is_aspect_preserving_scaling_, has_overscan_,
has_color_correction_matrix_, color_space_, display_name_, sys_path_,
std::move(clone_modes), edid_, cloned_current_mode, cloned_native_mode,
- product_id_, maximum_cursor_size_);
+ product_code_, year_of_manufacture_, maximum_cursor_size_);
}
std::string DisplaySnapshot::ToString() const {
return base::StringPrintf(
"id=%" PRId64
" current_mode=%s native_mode=%s origin=%s"
- " physical_size=%s, type=%s name=\"%s\" modes=(%s)",
+ " physical_size=%s, type=%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(), physical_size_.ToString().c_str(),
DisplayConnectionTypeString(type_).c_str(), display_name_.c_str(),
- ModeListString(modes_).c_str());
+ year_of_manufacture_, ModeListString(modes_).c_str());
}
// static
gfx::BufferFormat DisplaySnapshot::PrimaryFormat() {
- return gfx::BufferFormat::BGRX_8888;
+ return gfx::BufferFormat::BGRA_8888;
}
} // namespace display
diff --git a/chromium/ui/display/types/display_snapshot.h b/chromium/ui/display/types/display_snapshot.h
index cbb518fd94a..03b57e58f96 100644
--- a/chromium/ui/display/types/display_snapshot.h
+++ b/chromium/ui/display/types/display_snapshot.h
@@ -43,7 +43,8 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
const std::vector<uint8_t>& edid,
const DisplayMode* current_mode,
const DisplayMode* native_mode,
- int64_t product_id,
+ int64_t product_code,
+ int32_t year_of_manufacture,
const gfx::Size& maximum_cursor_size);
virtual ~DisplaySnapshot();
@@ -60,6 +61,7 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
return has_color_correction_matrix_;
}
const gfx::ColorSpace& color_space() const { return color_space_; }
+ void reset_color_space() { color_space_ = gfx::ColorSpace(); }
const std::string& display_name() const { return display_name_; }
const base::FilePath& sys_path() const { return sys_path_; }
const DisplayModeList& modes() const { return modes_; }
@@ -67,7 +69,8 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
const DisplayMode* current_mode() const { return current_mode_; }
void set_current_mode(const DisplayMode* mode) { current_mode_ = mode; }
const DisplayMode* native_mode() const { return native_mode_; }
- int64_t product_id() const { return product_id_; }
+ int64_t product_code() const { return product_code_; }
+ int32_t year_of_manufacture() const { return year_of_manufacture_; }
const gfx::Size& maximum_cursor_size() const { return maximum_cursor_size_; }
void add_mode(const DisplayMode* mode) { modes_.push_back(mode->Clone()); }
@@ -78,8 +81,8 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
// Returns a textual representation of this display state.
std::string ToString() const;
- // Used when no product id known.
- static const int64_t kInvalidProductID = -1;
+ // Used when no |product_code_| known.
+ static const int64_t kInvalidProductCode = -1;
// Returns the buffer format to be used for the primary plane buffer.
static gfx::BufferFormat PrimaryFormat();
@@ -102,7 +105,7 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
// Whether this display has advanced color correction available.
const bool has_color_correction_matrix_;
- const gfx::ColorSpace color_space_;
+ gfx::ColorSpace color_space_;
const std::string display_name_;
@@ -120,8 +123,10 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
// "Best" mode supported by the output.
const DisplayMode* const native_mode_;
- // Combination of manufacturer and product code.
- const int64_t product_id_;
+ // Combination of manufacturer id and product id.
+ const int64_t product_code_;
+
+ const int32_t year_of_manufacture_;
// Maximum supported cursor size on this display.
const gfx::Size maximum_cursor_size_;
diff --git a/chromium/ui/display/util/OWNERS b/chromium/ui/display/util/OWNERS
new file mode 100644
index 00000000000..3fd44a4deeb
--- /dev/null
+++ b/chromium/ui/display/util/OWNERS
@@ -0,0 +1,4 @@
+dcastagna@chromium.org
+mcasas@chromium.org
+
+# COMPONENT: OS>Kernel>Graphics
diff --git a/chromium/ui/display/util/edid_parser.cc b/chromium/ui/display/util/edid_parser.cc
index 8b310db96a8..9154e2f6cfa 100644
--- a/chromium/ui/display/util/edid_parser.cc
+++ b/chromium/ui/display/util/edid_parser.cc
@@ -10,100 +10,253 @@
#include "base/hash.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/sys_byteorder.h"
#include "third_party/skia/include/core/SkColorSpace.h"
+#include "ui/display/types/display_constants.h"
#include "ui/display/util/display_util.h"
#include "ui/gfx/geometry/size.h"
namespace display {
-namespace {
-
-// Returns a 32-bit identifier for this model of display, using
-// |manufacturer_id| and |product_code|.
-uint32_t GetProductID(uint16_t manufacturer_id, uint16_t product_code) {
- return ((static_cast<uint32_t>(manufacturer_id) << 16) |
- (static_cast<uint32_t>(product_code)));
+EdidParser::EdidParser(const std::vector<uint8_t>& edid_blob)
+ : manufacturer_id_(0),
+ product_id_(0),
+ year_of_manufacture_(display::kInvalidYearOfManufacture),
+ gamma_(0.0),
+ bits_per_channel_(-1),
+ primaries_({0}) {
+ ParseEdid(edid_blob);
}
-} // namespace
-
-bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
- uint8_t output_index,
- int64_t* display_id_out,
- int64_t* product_id_out) {
- uint16_t manufacturer_id = 0;
- uint16_t product_code = 0;
- std::string product_name;
+EdidParser::~EdidParser() = default;
- // ParseOutputDeviceData fails if it doesn't have product_name.
- ParseOutputDeviceData(edid, &manufacturer_id, &product_code, &product_name,
- nullptr, nullptr);
-
- if (manufacturer_id == 0)
- return false;
+uint32_t EdidParser::GetProductCode() const {
+ return ((static_cast<uint32_t>(manufacturer_id_) << 16) |
+ (static_cast<uint32_t>(product_id_)));
+}
+int64_t EdidParser::GetDisplayId(uint8_t output_index) const {
// Generates product specific value from product_name instead of product code.
- // See crbug.com/240341
- uint32_t product_code_hash =
- product_name.empty() ? 0 : base::Hash(product_name);
+ // See https://crbug.com/240341
+ const uint32_t product_code_hash =
+ display_name_.empty() ? 0 : base::Hash(display_name_);
// An ID based on display's index will be assigned later if this call fails.
- *display_id_out =
- GenerateDisplayID(manufacturer_id, product_code_hash, output_index);
- // |product_id_out| is 64-bit signed so it can store -1 as kInvalidProductID
- // and not match a valid product id which will all be in the lowest 32-bits.
- if (product_id_out)
- *product_id_out = GetProductID(manufacturer_id, product_code);
- return true;
+ return GenerateDisplayID(manufacturer_id_, product_code_hash, output_index);
+}
+
+// static
+void EdidParser::SplitProductCodeInManufacturerIdAndProductId(
+ int64_t product_code,
+ uint16_t* manufacturer_id,
+ uint16_t* product_id) {
+ DCHECK(manufacturer_id);
+ DCHECK(product_id);
+ // Undo GetProductCode() packing.
+ *product_id = product_code & 0xFFFF;
+ *manufacturer_id = (product_code >> 16) & 0xFFFF;
+}
+
+// static
+std::string EdidParser::ManufacturerIdToString(uint16_t manufacturer_id) {
+ // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+ // 2, Sep 2006, Sec 3.4.1 "ID Manufacturer Name: 2 Bytes". Essentially these
+ // are 3 5-bit ASCII characters packed in 2 bytes, where 1 means 'A', etc.
+ constexpr uint8_t kFiveBitAsciiMask = 0x1F;
+ constexpr char kFiveBitToAsciiOffset = 'A' - 1;
+ constexpr size_t kSecondLetterOffset = 5;
+ constexpr size_t kFirstLetterOffset = 10;
+
+ char out[4] = {};
+ out[2] = (manufacturer_id & kFiveBitAsciiMask) + kFiveBitToAsciiOffset;
+ out[1] = ((manufacturer_id >> kSecondLetterOffset) & kFiveBitAsciiMask) +
+ kFiveBitToAsciiOffset;
+ out[0] = ((manufacturer_id >> kFirstLetterOffset) & kFiveBitAsciiMask) +
+ kFiveBitToAsciiOffset;
+ return out;
+}
+
+// static
+std::string EdidParser::ProductIdToString(uint16_t product_id) {
+ // From "VESA Enhanced EDID Standard" Release A, Revision 2, Sep 2006, Sec
+ // 3.4.2 "ID Product Code: 2 Bytes": "The ID product code field, [...]
+ // contains a 2-byte manufacturer assigned product code. [...] The 2 byte
+ // number is stored in hex with the least significant byte listed first."
+ uint8_t lower_char = (product_id >> 8) & 0xFF;
+ uint8_t upper_char = product_id & 0xFF;
+ return base::StringPrintf("%02X%02X", upper_char, lower_char);
}
-bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
- uint16_t* manufacturer_id,
- uint16_t* product_code,
- std::string* human_readable_name,
- gfx::Size* active_pixel_out,
- gfx::Size* physical_display_size_out) {
+void EdidParser::ParseEdid(const std::vector<uint8_t>& edid) {
// See http://en.wikipedia.org/wiki/Extended_display_identification_data
// for the details of EDID data format. We use the following data:
// bytes 8-9: manufacturer EISA ID, in big-endian
// bytes 10-11: manufacturer product code, in little-endian
- // bytes 54-125: four descriptors (18-bytes each) which may contain
- // the display name.
constexpr size_t kManufacturerOffset = 8;
constexpr size_t kManufacturerLength = 2;
- constexpr size_t kProductCodeOffset = 10;
- constexpr size_t kProductCodeLength = 2;
- constexpr size_t kDescriptorOffset = 54;
- constexpr size_t kNumDescriptors = 4;
- constexpr size_t kDescriptorLength = 18;
- // The specifier types.
- constexpr uint8_t kMonitorNameDescriptor = 0xfc;
+ constexpr size_t kProductIdOffset = 10;
+ constexpr size_t kProductIdLength = 2;
- if (manufacturer_id) {
- if (edid.size() < kManufacturerOffset + kManufacturerLength) {
- LOG(ERROR) << "Too short EDID data: manufacturer id";
- return false;
- }
+ if (edid.size() < kManufacturerOffset + kManufacturerLength) {
+ LOG(ERROR) << "Too short EDID data: manufacturer id";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
+ }
+ // ICC filename is generated based on these ids. We always read this as big
+ // endian so that the file name matches bytes 8-11 as they appear in EDID.
+ manufacturer_id_ =
+ (edid[kManufacturerOffset] << 8) + edid[kManufacturerOffset + 1];
+
+ if (edid.size() < kProductIdOffset + kProductIdLength) {
+ LOG(ERROR) << "Too short EDID data: product id";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
+ }
+ product_id_ = (edid[kProductIdOffset] << 8) + edid[kProductIdOffset + 1];
- // ICC filename is generated based on these ids. We always read this as big
- // endian so that the file name matches bytes 8-11 as they appear in EDID.
- *manufacturer_id =
- (edid[kManufacturerOffset] << 8) + edid[kManufacturerOffset + 1];
+ // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+ // 2, Sep 2006, Sec 3.4.4 "Week and Year of Manufacture or Model Year: 2
+ // Bytes".
+ constexpr size_t kYearOfManufactureOffset = 17;
+ constexpr uint32_t kValidValueLowerBound = 0x10;
+ constexpr int32_t kYearOffset = 1990;
+
+ if (edid.size() < kYearOfManufactureOffset + 1) {
+ LOG(ERROR) << "Too short EDID data: year of manufacture";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
}
+ const uint8_t byte_data = edid[kYearOfManufactureOffset];
+ if (byte_data >= kValidValueLowerBound)
+ year_of_manufacture_ = byte_data + kYearOffset;
- if (product_code) {
- if (edid.size() < kProductCodeOffset + kProductCodeLength) {
- LOG(ERROR) << "Too short EDID data: manufacturer product code";
- return false;
- }
+ // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+ // 1, Feb 2000, Sec 3.6 "Basic Display Parameters and Features: 5 bytes"
+ static constexpr int kBitsPerChannelTable[] = {0, 6, 8, 10, 12, 14, 16, 0};
+
+ constexpr size_t kEDIDRevisionNumberOffset = 19;
+ constexpr uint8_t kEDIDRevision4Value = 4;
+
+ constexpr size_t kVideoInputDefinitionOffset = 20;
+ constexpr uint8_t kDigitalInfoMask = 0x80;
+ constexpr uint8_t kColorBitDepthMask = 0x70;
+ constexpr uint8_t kColorBitDepthOffset = 4;
+
+ if (edid.size() < kVideoInputDefinitionOffset + 1) {
+ LOG(ERROR) << "Too short EDID data: bits per channel";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
+ }
+ if (edid[kEDIDRevisionNumberOffset] >= kEDIDRevision4Value &&
+ (edid[kVideoInputDefinitionOffset] & kDigitalInfoMask)) {
+ // EDID needs to be revision 4 at least, and kDigitalInfoMask be set for
+ // the Video Input Definition entry to describe a digital interface.
+ bits_per_channel_ = kBitsPerChannelTable[(
+ (edid[kVideoInputDefinitionOffset] & kColorBitDepthMask) >>
+ kColorBitDepthOffset)];
+ }
+
+ // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+ // 2, Sep 2006, Sec. 3.6.3 "Display Transfer Characteristics (GAMMA ): 1 Byte"
+ constexpr size_t kGammaOffset = 23;
+ constexpr double kGammaMultiplier = 100.0;
+ constexpr double kGammaBias = 100.0;
+
+ if (edid.size() < kGammaOffset + 1) {
+ LOG(ERROR) << "Too short EDID data: gamma";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
+ }
+ if (edid[kGammaOffset] != 0xFF) {
+ // Otherwise the byte at kGammaOffset is 0xFF, gamma is stored elsewhere.
+ gamma_ = (edid[kGammaOffset] + kGammaBias) / kGammaMultiplier;
+ }
+
+ // Offsets, lengths, positions and masks are taken from [1] (or [2]).
+ // [1] http://en.wikipedia.org/wiki/Extended_display_identification_data
+ // [2] "VESA Enhanced EDID Standard " Release A, Revision 1, Feb 2000, Sec 3.7
+ // "Phosphor or Filter Chromaticity: 10 bytes"
+ constexpr size_t kChromaticityOffset = 25;
+ constexpr unsigned int kChromaticityLength = 10;
- *product_code =
- (edid[kProductCodeOffset] << 8) + edid[kProductCodeOffset + 1];
+ constexpr size_t kRedGreenLsbOffset = 25;
+ constexpr uint8_t kRedxLsbPosition = 6;
+ constexpr uint8_t kRedyLsbPosition = 4;
+ constexpr uint8_t kGreenxLsbPosition = 3;
+ constexpr uint8_t kGreenyLsbPosition = 0;
+
+ constexpr size_t kBlueWhiteLsbOffset = 26;
+ constexpr uint8_t kBluexLsbPosition = 6;
+ constexpr uint8_t kBlueyLsbPosition = 4;
+ constexpr uint8_t kWhitexLsbPosition = 3;
+ constexpr uint8_t kWhiteyLsbPosition = 0;
+
+ // All LSBits parts are 2 bits wide.
+ constexpr uint8_t kLsbMask = 0x3;
+
+ constexpr size_t kRedxMsbOffset = 27;
+ constexpr size_t kRedyMsbOffset = 28;
+ constexpr size_t kGreenxMsbOffset = 29;
+ constexpr size_t kGreenyMsbOffset = 30;
+ constexpr size_t kBluexMsbOffset = 31;
+ constexpr size_t kBlueyMsbOffset = 32;
+ constexpr size_t kWhitexMsbOffset = 33;
+ constexpr size_t kWhiteyMsbOffset = 34;
+
+ static_assert(
+ kChromaticityOffset + kChromaticityLength == kWhiteyMsbOffset + 1,
+ "EDID Parameter section length error");
+
+ if (edid.size() < kChromaticityOffset + kChromaticityLength) {
+ LOG(ERROR) << "Too short EDID data: chromaticity coordinates";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
}
- if (human_readable_name)
- human_readable_name->clear();
+ const uint8_t red_green_lsbs = edid[kRedGreenLsbOffset];
+ const uint8_t blue_white_lsbs = edid[kBlueWhiteLsbOffset];
+
+ // Recompose the 10b values by appropriately mixing the 8 MSBs and the 2 LSBs,
+ // then rescale to 1024;
+ primaries_.fRX = ((edid[kRedxMsbOffset] << 2) +
+ ((red_green_lsbs >> kRedxLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fRY = ((edid[kRedyMsbOffset] << 2) +
+ ((red_green_lsbs >> kRedyLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fGX = ((edid[kGreenxMsbOffset] << 2) +
+ ((red_green_lsbs >> kGreenxLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fGY = ((edid[kGreenyMsbOffset] << 2) +
+ ((red_green_lsbs >> kGreenyLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fBX = ((edid[kBluexMsbOffset] << 2) +
+ ((blue_white_lsbs >> kBluexLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fBY = ((edid[kBlueyMsbOffset] << 2) +
+ ((blue_white_lsbs >> kBlueyLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fWX = ((edid[kWhitexMsbOffset] << 2) +
+ ((blue_white_lsbs >> kWhitexLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ primaries_.fWY = ((edid[kWhiteyMsbOffset] << 2) +
+ ((blue_white_lsbs >> kWhiteyLsbPosition) & kLsbMask)) /
+ 1024.0f;
+ // TODO(mcasas): Up to two additional White Point coordinates can be provided
+ // in a Display Descriptor. Read them if we are not satisfied with |fWX| or
+ // |fWy|. https://crbug.com/771345.
+ // See http://en.wikipedia.org/wiki/Extended_display_identification_data
+ // for the details of EDID data format. We use the following data:
+ // bytes 54-125: four descriptors (18-bytes each) which may contain
+ // the display name.
+ constexpr size_t kDescriptorOffset = 54;
+ constexpr size_t kNumDescriptors = 4;
+ constexpr size_t kDescriptorLength = 18;
+ // The specifier types.
+ constexpr uint8_t kMonitorNameDescriptor = 0xfc;
+
+ display_name_.clear();
for (size_t i = 0; i < kNumDescriptors; ++i) {
if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength)
break;
@@ -114,7 +267,9 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
if (edid[offset] != 0 && edid[offset + 1] != 0) {
constexpr int kMaxResolution = 10080; // 8k display.
- if (active_pixel_out) {
+ // EDID may contain multiple DTD. Use the first one, that contains the
+ // highest resolution.
+ if (active_pixel_size_.IsEmpty()) {
constexpr size_t kHorizontalPixelLsbOffset = 2;
constexpr size_t kHorizontalPixelMsbOffset = 4;
constexpr size_t kVerticalPixelLsbOffset = 5;
@@ -128,25 +283,7 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
const uint8_t v_msb = edid[offset + kVerticalPixelMsbOffset];
int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution);
- active_pixel_out->SetSize(h_pixel, v_pixel);
- // EDID may contain multiple DTD. Use first one that
- // contains the highest resolution.
- active_pixel_out = nullptr;
- }
-
- if (physical_display_size_out) {
- constexpr size_t kHorizontalSizeLsbOffset = 12;
- constexpr size_t kVerticalSizeLsbOffset = 13;
- constexpr size_t kSizeMsbOffset = 14;
-
- const uint8_t h_lsb = edid[offset + kHorizontalSizeLsbOffset];
- const uint8_t v_lsb = edid[offset + kVerticalSizeLsbOffset];
-
- const uint8_t msb = edid[offset + kSizeMsbOffset];
- int h_size = h_lsb + ((msb & 0xF0) << 4);
- int v_size = v_lsb + ((msb & 0x0F) << 8);
- physical_display_size_out->SetSize(h_size, v_size);
- physical_display_size_out = nullptr;
+ active_pixel_size_.SetSize(h_pixel, v_pixel);
}
continue;
}
@@ -160,33 +297,24 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
// we should check bytes 0-2 and 4, since it may have other values in
// case that the descriptor contains other type of data.
if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 &&
- edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 &&
- human_readable_name) {
- std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]),
- kDescriptorLength - 5);
- base::TrimWhitespaceASCII(
- found_name, base::TRIM_TRAILING, human_readable_name);
+ edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) {
+ std::string name(reinterpret_cast<const char*>(&edid[offset + 5]),
+ kDescriptorLength - 5);
+ base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &display_name_);
continue;
}
}
- // Verify if the |human_readable_name| consists of printable characters only.
+ // Verify if the |display_name_| consists of printable characters only.
// TODO(oshima|muka): Consider replacing unprintable chars with white space.
- if (human_readable_name) {
- for (size_t i = 0; i < human_readable_name->size(); ++i) {
- char c = (*human_readable_name)[i];
- if (!isascii(c) || !isprint(c)) {
- human_readable_name->clear();
- LOG(ERROR) << "invalid EDID: human unreadable char in name";
- return false;
- }
+ for (const char c : display_name_) {
+ if (!isascii(c) || !isprint(c)) {
+ display_name_.clear();
+ LOG(ERROR) << "invalid EDID: human unreadable char in name";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
}
}
- return true;
-}
-
-bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, bool* flag) {
// See http://en.wikipedia.org/wiki/Extended_display_identification_data
// for the extension format of EDID. Also see EIA/CEA-861 spec for
// the format of the extensions and how video capability is encoded.
@@ -205,9 +333,11 @@ bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, bool* flag) {
constexpr uint8_t kITOverscanFlagPosition = 2;
constexpr uint8_t kCEOverscanFlagPosition = 0;
- if (edid.size() <= kNumExtensionsOffset)
- return false;
-
+ if (edid.size() < kNumExtensionsOffset + 1) {
+ LOG(ERROR) << "Too short EDID data: extensions";
+ // TODO(mcasas): add UMA, https://crbug.com/821393.
+ return; // Any other fields below are beyond this edid offset.
+ }
const uint8_t num_extensions = edid[kNumExtensionsOffset];
for (size_t i = 0; i < num_extensions; ++i) {
@@ -242,146 +372,15 @@ bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, bool* flag) {
continue;
}
- // The difference between preferred, IT, and CE video formats
- // doesn't matter. Set |flag| to true if any of these flags are true.
- *flag = (edid[data_offset + 2] & (1 << kPTOverscanFlagPosition)) ||
- (edid[data_offset + 2] & (1 << kITOverscanFlagPosition)) ||
- (edid[data_offset + 2] & (1 << kCEOverscanFlagPosition));
- return true;
+ // The difference between preferred, IT, and CE video formats doesn't
+ // matter. Set the flag to true if any of these flags are true.
+ overscan_flag_ =
+ (edid[data_offset + 2] & (1 << kPTOverscanFlagPosition)) ||
+ (edid[data_offset + 2] & (1 << kITOverscanFlagPosition)) ||
+ (edid[data_offset + 2] & (1 << kCEOverscanFlagPosition));
+ break;
}
}
-
- return false;
-}
-
-bool ParseChromaticityCoordinates(const std::vector<uint8_t>& edid,
- SkColorSpacePrimaries* primaries) {
- DCHECK(primaries);
-
- // Offsets, lengths, positions and masks are taken from [1] (or [2]).
- // [1] http://en.wikipedia.org/wiki/Extended_display_identification_data
- // [2] "VESA Enhanced EDID Standard " Release A, Revision 1, Feb 2000, Sec 3.7
- // "Phosphor or Filter Chromaticity: 10 bytes"
- constexpr size_t kChromaticityOffset = 25;
- constexpr unsigned int kChromaticityLength = 10;
-
- constexpr size_t kRedGreenLsbOffset = 25;
- constexpr uint8_t kRedxLsbPosition = 6;
- constexpr uint8_t kRedyLsbPosition = 4;
- constexpr uint8_t kGreenxLsbPosition = 3;
- constexpr uint8_t kGreenyLsbPosition = 0;
-
- constexpr size_t kBlueWhiteLsbOffset = 26;
- constexpr uint8_t kBluexLsbPosition = 6;
- constexpr uint8_t kBlueyLsbPosition = 4;
- constexpr uint8_t kWhitexLsbPosition = 3;
- constexpr uint8_t kWhiteyLsbPosition = 0;
-
- // All LSBits parts are 2 bits wide.
- constexpr uint8_t kLsbMask = 0x3;
-
- constexpr size_t kRedxMsbOffset = 27;
- constexpr size_t kRedyMsbOffset = 28;
- constexpr size_t kGreenxMsbOffset = 29;
- constexpr size_t kGreenyMsbOffset = 30;
- constexpr size_t kBluexMsbOffset = 31;
- constexpr size_t kBlueyMsbOffset = 32;
- constexpr size_t kWhitexMsbOffset = 33;
- constexpr size_t kWhiteyMsbOffset = 34;
-
- static_assert(
- kChromaticityOffset + kChromaticityLength == kWhiteyMsbOffset + 1,
- "EDID Parameter section length error");
-
- if (edid.size() < kChromaticityOffset + kChromaticityLength) {
- LOG(ERROR) << "Too short EDID data: chromaticity coordinates";
- return false;
- }
-
- const uint8_t red_green_lsbs = edid[kRedGreenLsbOffset];
- const uint8_t blue_white_lsbs = edid[kBlueWhiteLsbOffset];
-
- // Recompose the 10b values by appropriately mixing the 8 MSBs and the 2 LSBs,
- // then rescale to 1024;
- primaries->fRX = ((edid[kRedxMsbOffset] << 2) +
- ((red_green_lsbs >> kRedxLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fRY = ((edid[kRedyMsbOffset] << 2) +
- ((red_green_lsbs >> kRedyLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fGX = ((edid[kGreenxMsbOffset] << 2) +
- ((red_green_lsbs >> kGreenxLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fGY = ((edid[kGreenyMsbOffset] << 2) +
- ((red_green_lsbs >> kGreenyLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fBX = ((edid[kBluexMsbOffset] << 2) +
- ((blue_white_lsbs >> kBluexLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fBY = ((edid[kBlueyMsbOffset] << 2) +
- ((blue_white_lsbs >> kBlueyLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fWX = ((edid[kWhitexMsbOffset] << 2) +
- ((blue_white_lsbs >> kWhitexLsbPosition) & kLsbMask)) /
- 1024.0f;
- primaries->fWY = ((edid[kWhiteyMsbOffset] << 2) +
- ((blue_white_lsbs >> kWhiteyLsbPosition) & kLsbMask)) /
- 1024.0f;
-
- // TODO(mcasas): Up to two additional White Point coordinates can be provided
- // in a Display Descriptor.Read them if we are not satisfied with |fWX| or
- // |FWy|. https://crbug.com/771345.
- return true;
-}
-
-DISPLAY_UTIL_EXPORT bool ParseGammaValue(const std::vector<uint8_t>& edid,
- double* gamma) {
- // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
- // 2, Sep 2006, Sec. 3.6.3 "Display Transfer Characteristics (GAMMA ): 1 Byte"
- constexpr size_t kGammaOffset = 23;
- constexpr double kGammaMultiplier = 100.0;
- constexpr double kGammaBias = 100.0;
-
- if (edid.size() < kGammaOffset + 1) {
- LOG(ERROR) << "Too short EDID data: gamma";
- return false;
- }
- if (edid[kGammaOffset] == 0xFF) // Gamma is stored elsewhere.
- return false;
- DCHECK(gamma);
- *gamma = (edid[kGammaOffset] + kGammaBias) / kGammaMultiplier;
- return true;
-}
-
-DISPLAY_UTIL_EXPORT bool ParseBitsPerChannel(const std::vector<uint8_t>& edid,
- int* bits_per_channel) {
- // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
- // 1, Feb 2000, Sec 3.6 "Basic Display Parameters and Features: 5 bytes"
- static constexpr int kBitsPerChannelTable[] = {0, 6, 8, 10, 12, 14, 16, 0};
-
- constexpr size_t kEDIDRevisionNumberOffset = 19;
- constexpr uint8_t kEDIDRevision4Value = 4;
-
- constexpr size_t kVideoInputDefinitionOffset = 20;
- constexpr uint8_t kDigitalInfoMask = 0x80;
- constexpr uint8_t kColorBitDepthMask = 0x70;
- constexpr uint8_t kColorBitDepthOffset = 4;
-
- if (edid.size() < kVideoInputDefinitionOffset + 1) {
- LOG(ERROR) << "Too short EDID data: gamma";
- return false;
- }
- // EDID needs to be revision 4 at least, and kDigitalInfoMask be set for
- // the Video Input Definition entry to describe a digital interface.
- if (edid[kEDIDRevisionNumberOffset] < kEDIDRevision4Value ||
- !(edid[kVideoInputDefinitionOffset] & kDigitalInfoMask)) {
- return false;
- }
- DCHECK(bits_per_channel);
- *bits_per_channel = kBitsPerChannelTable[(
- (edid[kVideoInputDefinitionOffset] & kColorBitDepthMask) >>
- kColorBitDepthOffset)];
- return true;
}
} // namespace display
diff --git a/chromium/ui/display/util/edid_parser.h b/chromium/ui/display/util/edid_parser.h
index 17e67debfe1..5323f527da5 100644
--- a/chromium/ui/display/util/edid_parser.h
+++ b/chromium/ui/display/util/edid_parser.h
@@ -11,59 +11,68 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/optional.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/display/util/display_util_export.h"
-
-namespace gfx {
-class Size;
-}
-
-struct SkColorSpacePrimaries;
-
-// EDID (Extended Display Identification Data) is a format for monitor
-// metadata. This provides a parser for the data.
+#include "ui/gfx/geometry/size.h"
namespace display {
-// Generates the display id and product id for the pair of |edid| and |index|,
-// and store in |display_id_out| and |product_id_out|. Returns true if the
-// display id is successfully generated, or false otherwise.
-DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
- uint8_t index,
- int64_t* display_id_out,
- int64_t* product_id_out);
-
-// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|,
-// |product_code|, |human_readable_name|, |active_pixel_out| and
-// |physical_display_size_out|, then returns true. nullptr can be passed for
-// unwanted output parameters. Some devices (especially internal displays) may
-// not have the field for |human_readable_name|, and it will return true in
-// that case.
-DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData(
- const std::vector<uint8_t>& edid,
- uint16_t* manufacturer_id,
- uint16_t* product_code,
- std::string* human_readable_name,
- gfx::Size* active_pixel_out,
- gfx::Size* physical_display_size_out);
-
-DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
- const std::vector<uint8_t>& edid,
- bool* flag);
-
-// Extracts from |edid| the |primaries| chromaticity coordinates (CIE xy
-// coordinates for Red, Green and Blue channels and for the White Point).
-DISPLAY_UTIL_EXPORT bool ParseChromaticityCoordinates(
- const std::vector<uint8_t>& edid,
- SkColorSpacePrimaries* primaries) WARN_UNUSED_RESULT;
-
-// Extracts the gamma value from |edid| and returns it, or returns 0.0.
-DISPLAY_UTIL_EXPORT bool ParseGammaValue(const std::vector<uint8_t>& edid,
- double* gamma) WARN_UNUSED_RESULT;
-
-// Extracts the bits per channel from |edid| and returns it, or returns 0.
-DISPLAY_UTIL_EXPORT bool ParseBitsPerChannel(const std::vector<uint8_t>& edid,
- int* bits_per_channel)
- WARN_UNUSED_RESULT;
+// This class parses a EDID (Extended Display Identification Data) binary blob
+// passed on constructor, and provides access to the parsed information, plus
+// a few utility postprocessings.
+class DISPLAY_UTIL_EXPORT EdidParser {
+ public:
+ explicit EdidParser(const std::vector<uint8_t>& edid_blob);
+ ~EdidParser();
+
+ uint16_t manufacturer_id() const { return manufacturer_id_; }
+ uint16_t product_id() const { return product_id_; }
+ const std::string& display_name() const { return display_name_; }
+ const gfx::Size& active_pixel_size() const { return active_pixel_size_; }
+ int32_t year_of_manufacture() const { return year_of_manufacture_; }
+ bool has_overscan_flag() const { return overscan_flag_.has_value(); }
+ bool overscan_flag() const { return overscan_flag_.value(); }
+ double gamma() const { return gamma_; }
+ int32_t bits_per_channel() const { return bits_per_channel_; }
+ const SkColorSpacePrimaries& primaries() const { return primaries_; }
+
+ // Returns a 32-bit identifier for this display |manufacturer_id_| and
+ // |product_id_|.
+ uint32_t GetProductCode() const;
+
+ // Generates a unique display id out of a mix of |manufacturer_id_|, hashed
+ // |display_name_| if available, and |output_index|.
+ int64_t GetDisplayId(uint8_t output_index) const;
+
+ // Splits the |product_code| (as returned by GetDisplayId()) into its
+ // constituents |manufacturer_id| and |product_id|.
+ static void SplitProductCodeInManufacturerIdAndProductId(
+ int64_t product_code,
+ uint16_t* manufacturer_id,
+ uint16_t* product_id);
+ // Extracts the three letter Manufacturer ID out of |manufacturer_id|.
+ static std::string ManufacturerIdToString(uint16_t manufacturer_id);
+ // Extracts the 2 Byte Product ID as hex out of |product_id|.
+ static std::string ProductIdToString(uint16_t product_id);
+
+ private:
+ // Parses |edid_blob|, filling up as many as possible fields below.
+ void ParseEdid(const std::vector<uint8_t>& edid);
+
+ uint16_t manufacturer_id_;
+ uint16_t product_id_;
+ std::string display_name_;
+ // Active pixel size from the first detailed timing descriptor in the EDID.
+ gfx::Size active_pixel_size_;
+ int32_t year_of_manufacture_;
+ base::Optional<bool> overscan_flag_;
+ double gamma_;
+ int bits_per_channel_;
+ SkColorSpacePrimaries primaries_;
+
+ DISALLOW_COPY_AND_ASSIGN(EdidParser);
+};
} // namespace display
diff --git a/chromium/ui/display/util/edid_parser_fuzzer.cc b/chromium/ui/display/util/edid_parser_fuzzer.cc
index 7ae1b8f46e4..d3d8f0c12e3 100644
--- a/chromium/ui/display/util/edid_parser_fuzzer.cc
+++ b/chromium/ui/display/util/edid_parser_fuzzer.cc
@@ -23,15 +23,7 @@ Environment* env = new Environment();
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::vector<uint8_t> edid;
edid.assign(data, data + size);
- uint16_t manufacturer_id, product_code;
- std::string human_readable_name;
- gfx::Size active_pixel_size, physical_display_size;
- bool overscan;
-
- display::ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- &human_readable_name, &active_pixel_size,
- &physical_display_size);
-
- display::ParseOutputOverscanFlag(edid, &overscan);
+ // Ctor already parses |edid|, which is what we want here.
+ display::EdidParser edid_parser(edid);
return 0;
}
diff --git a/chromium/ui/display/util/edid_parser_unittest.cc b/chromium/ui/display/util/edid_parser_unittest.cc
index 7511a13cdab..8d3073361ab 100644
--- a/chromium/ui/display/util/edid_parser_unittest.cc
+++ b/chromium/ui/display/util/edid_parser_unittest.cc
@@ -12,21 +12,20 @@
#include "base/numerics/ranges.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
+#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/size.h"
using ::testing::AssertionFailure;
using ::testing::AssertionSuccess;
+using ::testing::TestWithParam;
+using ::testing::ValuesIn;
namespace display {
namespace {
-// Returns the number of characters in the string literal but doesn't count its
-// terminator NULL byte.
-#define charsize(str) (arraysize(str) - 1)
-
// Sample EDID data extracted from real devices.
-const unsigned char kNormalDisplay[] =
+constexpr unsigned char kNormalDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
"\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
"\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
@@ -35,8 +34,9 @@ const unsigned char kNormalDisplay[] =
"\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
"\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
"\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
+constexpr size_t kNormalDisplayLength = arraysize(kNormalDisplay);
-const unsigned char kInternalDisplay[] =
+constexpr unsigned char kInternalDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
"\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
"\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
@@ -45,8 +45,9 @@ const unsigned char kInternalDisplay[] =
"\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
"\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
"\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
+constexpr size_t kInternalDisplayLength = arraysize(kInternalDisplay);
-const unsigned char kOverscanDisplay[] =
+constexpr unsigned char kOverscanDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x2d\xfe\x08\x00\x00\x00\x00"
"\x29\x15\x01\x03\x80\x10\x09\x78\x0a\xee\x91\xa3\x54\x4c\x99\x26"
"\x0f\x50\x54\xbd\xef\x80\x71\x4f\x81\xc0\x81\x00\x81\x80\x95\x00"
@@ -63,9 +64,10 @@ const unsigned char kOverscanDisplay[] =
"\x5a\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
+constexpr size_t kOverscanDisplayLength = arraysize(kOverscanDisplay);
// The EDID info misdetecting overscan once. see crbug.com/226318
-const unsigned char kMisdetectedDisplay[] =
+constexpr unsigned char kMisdetectedDisplay[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x10\xac\x64\x40\x4c\x30\x30\x32"
"\x0c\x15\x01\x03\x80\x40\x28\x78\xea\x8d\x85\xad\x4f\x35\xb1\x25"
"\x0e\x50\x54\xa5\x4b\x00\x71\x4f\x81\x00\x81\x80\xd1\x00\xa9\x40"
@@ -82,8 +84,9 @@ const unsigned char kMisdetectedDisplay[] =
"\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\x81\x91\x21\x00\x00\x1e\x8c"
"\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x81\x91\x21\x00\x00"
"\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94";
+constexpr size_t kMisdetectedDisplayLength = arraysize(kMisdetectedDisplay);
-const unsigned char kLP2565A[] =
+constexpr unsigned char kLP2565A[] =
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x76\x26\x01\x01\x01\x01"
"\x02\x12\x01\x03\x80\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26"
"\x0F\x50\x54\xA5\x6B\x80\x81\x40\x81\x80\x81\x99\x71\x00\xA9\x00"
@@ -92,8 +95,9 @@ const unsigned char kLP2565A[] =
"\x5E\x11\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\xA4";
+constexpr size_t kLP2565ALength = arraysize(kLP2565A);
-const unsigned char kLP2565B[] =
+constexpr unsigned char kLP2565B[] =
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x75\x26\x01\x01\x01\x01"
"\x02\x12\x01\x03\x6E\x34\x21\x78\xEE\xEF\x95\xA3\x54\x4C\x9B\x26"
"\x0F\x50\x54\xA5\x6B\x80\x81\x40\x71\x00\xA9\x00\xA9\x40\xA9\x4F"
@@ -102,9 +106,10 @@ const unsigned char kLP2565B[] =
"\x5E\x15\x00\x0A\x20\x20\x20\x20\x20\x20\x00\x00\x00\xFC\x00\x48"
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
+constexpr size_t kLP2565BLength = arraysize(kLP2565B);
// HP z32x monitor.
-const unsigned char kHPz32x[] =
+constexpr unsigned char kHPz32x[] =
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x22\xF0\x75\x32\x01\x01\x01\x01"
"\x1B\x1B\x01\x04\xB5\x46\x27\x78\x3A\x8D\x15\xAC\x51\x32\xB8\x26"
"\x0B\x50\x54\x21\x08\x00\xD1\xC0\xA9\xC0\x81\xC0\xD1\x00\xB3\x00"
@@ -121,9 +126,10 @@ const unsigned char kHPz32x[] =
"\x00\xA0\xA0\x40\x2E\x60\x20\x30\x63\x00\xB9\x88\x21\x00\x00\x1C"
"\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20\x36\x00\xB9\x88\x21\x00"
"\x00\x1A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3E";
+constexpr size_t kHPz32xLength = arraysize(kHPz32x);
// Chromebook Samus internal display.
-const unsigned char kSamus[] =
+constexpr unsigned char kSamus[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x30\xe4\x2e\x04\x00\x00\x00\x00"
"\x00\x18\x01\x04\xa5\x1b\x12\x96\x02\x4f\xd5\xa2\x59\x52\x93\x26"
"\x17\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
@@ -132,9 +138,10 @@ const unsigned char kSamus[] =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x00\x4c"
"\x47\x20\x44\x69\x73\x70\x6c\x61\x79\x0a\x20\x20\x00\x00\x00\xfe"
"\x00\x4c\x50\x31\x32\x39\x51\x45\x32\x2d\x53\x50\x41\x31\x00\x6c";
+constexpr size_t kSamusLength = arraysize(kSamus);
// Chromebook Eve internal display.
-const unsigned char kEve[] =
+constexpr unsigned char kEve[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x4d\x10\x8a\x14\x00\x00\x00\x00"
"\x16\x1b\x01\x04\xa5\x1a\x11\x78\x06\xde\x50\xa3\x54\x4c\x99\x26"
"\x0f\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
@@ -143,13 +150,29 @@ const unsigned char kEve[] =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc"
"\x00\x4c\x51\x31\x32\x33\x50\x31\x4a\x58\x33\x32\x0a\x20\x00\xb6";
+constexpr size_t kEveLength = arraysize(kEve);
+
+constexpr SkColorSpacePrimaries kNormalDisplayPrimaries = {
+ 0.6777f, 0.3086f, 0.2080f, 0.6923f, 0.1465f, 0.0546f, 0.3125f, 0.3291f};
+constexpr SkColorSpacePrimaries kInternalDisplayPrimaries = {
+ 0.5849f, 0.3603f, 0.3769f, 0.5654f, 0.1552f, 0.0996f, 0.3125f, 0.3291f};
+constexpr SkColorSpacePrimaries kOverscanDisplayPrimaries = {
+ 0.6396f, 0.3291f, 0.2978f, 0.5996f, 0.1494f, 0.0595f, 0.3144f, 0.3291f};
+constexpr SkColorSpacePrimaries kMisdetectedDisplayPrimaries = {
+ 0.6777f, 0.3086f, 0.2080f, 0.6923f, 0.1465f, 0.0546f, 0.3125f, 0.3291f};
+constexpr SkColorSpacePrimaries kLP2565APrimaries = {
+ 0.6396f, 0.3291f, 0.2978f, 0.6083f, 0.1494f, 0.0595f, 0.3144f, 0.3291f};
+constexpr SkColorSpacePrimaries kLP2565BPrimaries = {
+ 0.6396f, 0.3291f, 0.2978f, 0.6083f, 0.1494f, 0.0595f, 0.3144f, 0.3291f};
+constexpr SkColorSpacePrimaries kHPz32xPrimaries = {
+ 0.6738f, 0.3164f, 0.1962f, 0.7197f, 0.1484f, 0.0439f, 0.3144f, 0.3291f};
+constexpr SkColorSpacePrimaries kSamusPrimaries = {
+ 0.6337f, 0.3476f, 0.3212f, 0.5771f, 0.1513f, 0.0908f, 0.3144f, 0.3291f};
+constexpr SkColorSpacePrimaries kEvePrimaries = {
+ 0.6396f, 0.3291f, 0.2998f, 0.5996f, 0.1494f, 0.0595f, 0.3144f, 0.3281f};
-void Reset(gfx::Size* pixel, gfx::Size* size) {
- pixel->SetSize(0, 0);
- size->SetSize(0, 0);
-}
// Chromaticity primaries in EDID are specified with 10 bits precision.
-const static float kPrimariesPrecision = 0.001f;
+constexpr static float kPrimariesPrecision = 0.001f;
::testing::AssertionResult SkColorSpacePrimariesEquals(
const char* lhs_expr,
@@ -177,286 +200,96 @@ const static float kPrimariesPrecision = 0.001f;
} // namespace
-TEST(EDIDParserTest, ParseOverscanFlag) {
- bool flag = false;
- std::vector<uint8_t> edid(
- kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- EXPECT_FALSE(ParseOutputOverscanFlag(edid, &flag));
-
- flag = false;
- edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- EXPECT_FALSE(ParseOutputOverscanFlag(edid, &flag));
-
- flag = false;
- edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
- EXPECT_TRUE(ParseOutputOverscanFlag(edid, &flag));
- EXPECT_TRUE(flag);
-
- flag = false;
- edid.assign(
- kMisdetectedDisplay, kMisdetectedDisplay + charsize(kMisdetectedDisplay));
- EXPECT_FALSE(ParseOutputOverscanFlag(edid, &flag));
-
- flag = false;
- // Copy |kOverscanDisplay| and set flags to false in it. The overscan flags
- // are embedded at byte 150 in this specific example. Fix here too when the
- // contents of kOverscanDisplay is altered.
- edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
- edid[150] = '\0';
- EXPECT_TRUE(ParseOutputOverscanFlag(edid, &flag));
- EXPECT_FALSE(flag);
-}
-
-TEST(EDIDParserTest, ParseBrokenOverscanData) {
- // Do not fill valid data here because it anyway fails to parse the data.
- std::vector<uint8_t> data;
- bool flag = false;
- EXPECT_FALSE(ParseOutputOverscanFlag(data, &flag));
- data.assign(126, '\0');
- EXPECT_FALSE(ParseOutputOverscanFlag(data, &flag));
-
- // extending data because ParseOutputOverscanFlag() will access the data.
- data.assign(128, '\0');
- // The number of CEA extensions is stored at byte 126.
- data[126] = '\x01';
- EXPECT_FALSE(ParseOutputOverscanFlag(data, &flag));
-
- data.assign(150, '\0');
- data[126] = '\x01';
- EXPECT_FALSE(ParseOutputOverscanFlag(data, &flag));
-}
-
-TEST(EDIDParserTest, ParseEDID) {
- uint16_t manufacturer_id = 0;
- uint16_t product_code = 0;
- std::string human_readable_name;
- std::vector<uint8_t> edid(
- kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- gfx::Size pixel;
- gfx::Size size;
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- &human_readable_name, &pixel, &size));
- EXPECT_EQ(0x22f0u, manufacturer_id);
- EXPECT_EQ(0x6c28u, product_code);
- EXPECT_EQ("HP ZR30w", human_readable_name);
- EXPECT_EQ("2560x1600", pixel.ToString());
- EXPECT_EQ("641x400", size.ToString());
-
- manufacturer_id = 0;
- product_code = 0;
- human_readable_name.clear();
- Reset(&pixel, &size);
- edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
-
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- nullptr, &pixel, &size));
- EXPECT_EQ(0x4ca3u, manufacturer_id);
- EXPECT_EQ(0x4231u, product_code);
- EXPECT_EQ("", human_readable_name);
- EXPECT_EQ("1280x800", pixel.ToString());
- EXPECT_EQ("261x163", size.ToString());
-
- // Internal display doesn't have name.
- EXPECT_TRUE(ParseOutputDeviceData(edid, nullptr, nullptr,
- &human_readable_name, &pixel, &size));
- EXPECT_TRUE(human_readable_name.empty());
-
- manufacturer_id = 0;
- product_code = 0;
- human_readable_name.clear();
- Reset(&pixel, &size);
- edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- &human_readable_name, &pixel, &size));
- EXPECT_EQ(0x4c2du, manufacturer_id);
- EXPECT_EQ(0xfe08u, product_code);
- EXPECT_EQ("SAMSUNG", human_readable_name);
- EXPECT_EQ("1920x1080", pixel.ToString());
- EXPECT_EQ("160x90", size.ToString());
-}
-
-TEST(EDIDParserTest, ParseBrokenEDID) {
- uint16_t manufacturer_id = 0;
- uint16_t product_code = 0;
- std::string human_readable_name;
- std::vector<uint8_t> edid;
-
- gfx::Size dummy;
-
- // length == 0
- EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- &human_readable_name, &dummy, &dummy));
-
- // name is broken. Copying kNormalDisplay and substitute its name data by
- // some control code.
- edid.assign(kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
-
- // display's name data is embedded in byte 95-107 in this specific example.
- // Fix here too when the contents of kNormalDisplay is altered.
- edid[97] = '\x1b';
- EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id, nullptr,
- &human_readable_name, &dummy, &dummy));
-
- // If |human_readable_name| isn't specified, it skips parsing the name.
- manufacturer_id = 0;
- product_code = 0;
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
- nullptr, &dummy, &dummy));
- EXPECT_EQ(0x22f0u, manufacturer_id);
- EXPECT_EQ(0x6c28u, product_code);
-}
-
-TEST(EDIDParserTest, GetDisplayId) {
- // EDID of kLP2565A and B are slightly different but actually the same device.
- int64_t id1 = -1;
- int64_t id2 = -1;
- int64_t product_id1 = -1;
- int64_t product_id2 = -1;
- std::vector<uint8_t> edid(kLP2565A, kLP2565A + charsize(kLP2565A));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id1, &product_id1));
- edid.assign(kLP2565B, kLP2565B + charsize(kLP2565B));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id2, &product_id2));
- EXPECT_EQ(id1, id2);
- // The product code in the two EDIDs varies.
- EXPECT_NE(product_id1, product_id2);
- EXPECT_EQ(0x22f07626, product_id1);
- EXPECT_EQ(0x22f07526, product_id2);
- EXPECT_NE(-1, id1);
- EXPECT_NE(-1, product_id1);
+struct TestParams {
+ uint16_t manufacturer_id;
+ uint16_t product_id;
+ std::string display_name;
+ gfx::Size active_pixel_size;
+ int32_t year_of_manufacture;
+ bool overscan_flag;
+ double gamma;
+ int bits_per_channel;
+ SkColorSpacePrimaries primaries;
+
+ uint32_t product_code;
+ int64_t display_id_zero;
+
+ std::string manufacturer_id_string;
+ std::string product_id_string;
+
+ const unsigned char* edid_blob;
+ size_t edid_blob_length;
+} kTestCases[] = {
+ {0x22f0u, 0x6c28u, "HP ZR30w", gfx::Size(2560, 1600), 2012, false, 2.2, 10,
+ kNormalDisplayPrimaries, 586181672, 9834734971736576, "HWP", "286C",
+ kNormalDisplay, kNormalDisplayLength},
+ {0x4ca3u, 0x4231u, "", gfx::Size(1280, 800), 2011, false, 2.2, -1,
+ kInternalDisplayPrimaries, 1285767729, 21571318625337344, "SEC", "3142",
+ kInternalDisplay, kInternalDisplayLength},
+ {0x4c2du, 0xfe08u, "SAMSUNG", gfx::Size(1920, 1080), 2011, true, 2.2, -1,
+ kOverscanDisplayPrimaries, 1278082568, 21442559853606400, "SAM", "08FE",
+ kOverscanDisplay, kOverscanDisplayLength},
+ {0x10ACu, 0x6440u, "DELL U3011", gfx::Size(1920, 1200), 2011, false, 2.2,
+ -1, kMisdetectedDisplayPrimaries, 279733312, 4692848143772416, "DEL",
+ "4064", kMisdetectedDisplay, kMisdetectedDisplayLength},
+ {0x22f0u, 0x7626u, "HP LP2465", gfx::Size(1920, 1200), 2008, false, 2.2, -1,
+ kLP2565APrimaries, 586184230, 9834630174887424, "HWP", "2676", kLP2565A,
+ kLP2565ALength},
+ {0x22f0u, 0x7526u, "HP LP2465", gfx::Size(1920, 1200), 2008, false, 2.2, -1,
+ kLP2565BPrimaries, 586183974, 9834630174887424, "HWP", "2675", kLP2565B,
+ kLP2565BLength},
+ {0x22f0u, 0x7532u, "HP Z32x", gfx::Size(3840, 2160), 2017, false, 2.2, 10,
+ kHPz32xPrimaries, 586183986, 9834799315992832, "HWP", "3275", kHPz32x,
+ kHPz32xLength},
+ {0x30E4u, 0x2E04u, "", gfx::Size(2560, 1700), 2014, false, 2.5, 8,
+ kSamusPrimaries, 820260356, 13761487533244416, "LGD", "042E", kSamus,
+ kSamusLength},
+ {0x4D10u, 0x8A14u, "LQ123P1JX32", gfx::Size(2400, 1600), 2017, false, 2.2,
+ 8, kEvePrimaries, 1292929556, 21692109949126656, "SHP", "148A", kEve,
+ kEveLength},
+
+ // Empty Edid, which is tantamount to error.
+ {0, 0, "", gfx::Size(0, 0), display::kInvalidYearOfManufacture, false, 0.0,
+ -1, SkColorSpacePrimaries(), 0, 0, "@@@", "0000", nullptr, 0u},
+};
+
+class EDIDParserTest : public TestWithParam<TestParams> {
+ public:
+ EDIDParserTest()
+ : parser_(std::vector<uint8_t>(
+ GetParam().edid_blob,
+ GetParam().edid_blob + GetParam().edid_blob_length)) {}
+
+ const EdidParser parser_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EDIDParserTest);
+};
+
+TEST_P(EDIDParserTest, ParseEdids) {
+ EXPECT_EQ(parser_.manufacturer_id(), GetParam().manufacturer_id);
+ EXPECT_EQ(parser_.product_id(), GetParam().product_id);
+ EXPECT_EQ(parser_.display_name(), GetParam().display_name);
+ EXPECT_EQ(parser_.active_pixel_size(), GetParam().active_pixel_size);
+ EXPECT_EQ(parser_.year_of_manufacture(), GetParam().year_of_manufacture);
+ EXPECT_EQ(parser_.has_overscan_flag(), GetParam().overscan_flag);
+ if (parser_.has_overscan_flag())
+ EXPECT_EQ(parser_.overscan_flag(), GetParam().overscan_flag);
+ EXPECT_DOUBLE_EQ(parser_.gamma(), GetParam().gamma);
+ EXPECT_EQ(parser_.bits_per_channel(), GetParam().bits_per_channel);
+ EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, parser_.primaries(),
+ GetParam().primaries);
+
+ EXPECT_EQ(parser_.GetProductCode(), GetParam().product_code);
+ EXPECT_EQ(parser_.GetDisplayId(0 /* product_index */),
+ GetParam().display_id_zero);
+
+ EXPECT_EQ(EdidParser::ManufacturerIdToString(parser_.manufacturer_id()),
+ GetParam().manufacturer_id_string);
+ EXPECT_EQ(EdidParser::ProductIdToString(parser_.product_id()),
+ GetParam().product_id_string);
}
-TEST(EDIDParserTest, GetDisplayIdFromInternal) {
- int64_t id = -1;
- int64_t product_id = -1;
- std::vector<uint8_t> edid(
- kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id, &product_id));
- EXPECT_NE(-1, id);
- EXPECT_NE(-1, product_id);
-}
-
-TEST(EDIDParserTest, GetDisplayIdFailure) {
- int64_t id = -1;
- int64_t product_id = -1;
- std::vector<uint8_t> edid;
- EXPECT_FALSE(GetDisplayIdFromEDID(edid, 0, &id, &product_id));
- EXPECT_EQ(-1, id);
- EXPECT_EQ(-1, product_id);
-}
-
-TEST(EDIDParserTest, ParseChromaticityCoordinates) {
- const std::vector<uint8_t> edid_normal_display(
- kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- SkColorSpacePrimaries primaries_normal_display;
- EXPECT_TRUE(ParseChromaticityCoordinates(edid_normal_display,
- &primaries_normal_display));
- // Color primaries associated to |kNormalDisplay|; they don't correspond to
- // any standard color gamut.
- const SkColorSpacePrimaries kNormalDisplayPrimaries = {
- 0.6777f, 0.3086f, 0.2080f, 0.6923f, 0.1465f, 0.0546f, 0.3125f, 0.3291f};
- EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, primaries_normal_display,
- kNormalDisplayPrimaries);
-
- const std::vector<uint8_t> edid_internal_display(
- kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- SkColorSpacePrimaries primaries_internal_display;
- EXPECT_TRUE(ParseChromaticityCoordinates(edid_internal_display,
- &primaries_internal_display));
- // Color primaries associated to |kInternalDisplay|; they don't correspond to
- // any standard color gamut.
- const SkColorSpacePrimaries kInternalDisplayPrimaries = {
- 0.5849f, 0.3603f, 0.3769f, 0.5654f, 0.1552f, 0.0996f, 0.3125f, 0.3291f};
- EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, primaries_internal_display,
- kInternalDisplayPrimaries);
-
- const std::vector<uint8_t> edid_hpz32x(kHPz32x, kHPz32x + charsize(kHPz32x));
- SkColorSpacePrimaries primaries_hpz32x;
- EXPECT_TRUE(ParseChromaticityCoordinates(edid_hpz32x, &primaries_hpz32x));
- // Color primaries associated to |kHPz32x|; they don't correspond to
- // any standard color gamut.
- const SkColorSpacePrimaries kHPz32xPrimaries = {
- 0.6738f, 0.3164f, 0.1962f, 0.7197f, 0.1484f, 0.0439f, 0.3144f, 0.3291f};
- EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, primaries_hpz32x,
- kHPz32xPrimaries);
-
- const std::vector<uint8_t> edid_samus(kSamus, kSamus + charsize(kSamus));
- SkColorSpacePrimaries primaries_samus;
- EXPECT_TRUE(ParseChromaticityCoordinates(edid_samus, &primaries_samus));
- // Color primaries associated to Samus Chromebook, very similar to BT.709.
- const SkColorSpacePrimaries kSamusPrimaries = {
- 0.6337f, 0.3476f, 0.3212f, 0.5771f, 0.1513f, 0.0908f, 0.3144f, 0.3291f};
- EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, primaries_samus,
- kSamusPrimaries);
-
- const std::vector<uint8_t> edid_eve(kEve, kEve + charsize(kEve));
- SkColorSpacePrimaries primaries_eve;
- EXPECT_TRUE(ParseChromaticityCoordinates(edid_eve, &primaries_eve));
- // Color primaries associated to Eve Chromebook, very similar to BT.709.
- const SkColorSpacePrimaries kEvePrimaries = {
- 0.6396f, 0.3291f, 0.2998f, 0.5996f, 0.1494f, 0.0595f, 0.3144f, 0.3281f};
- EXPECT_PRED_FORMAT2(SkColorSpacePrimariesEquals, primaries_eve,
- kEvePrimaries);
-}
-
-TEST(EDIDParserTest, ParseGammaValue) {
- const std::vector<uint8_t> edid_normal_display(
- kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- double edid_normal_display_gamma = 0.0;
- EXPECT_TRUE(ParseGammaValue(edid_normal_display, &edid_normal_display_gamma));
- EXPECT_DOUBLE_EQ(2.2, edid_normal_display_gamma);
-
- const std::vector<uint8_t> edid_internal_display(
- kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- double edid_internal_display_gamma = 0.0;
- EXPECT_TRUE(
- ParseGammaValue(edid_internal_display, &edid_internal_display_gamma));
- EXPECT_DOUBLE_EQ(2.2, edid_internal_display_gamma);
-
- const std::vector<uint8_t> edid_hpz32x(kHPz32x, kHPz32x + charsize(kHPz32x));
- double edid_hpz32x_gamma = 0.0;
- EXPECT_TRUE(ParseGammaValue(edid_hpz32x, &edid_hpz32x_gamma));
- EXPECT_DOUBLE_EQ(2.2, edid_hpz32x_gamma);
-
- const std::vector<uint8_t> edid_samus(kSamus, kSamus + charsize(kSamus));
- double edid_samus_gamma = 0.0;
- EXPECT_TRUE(ParseGammaValue(edid_samus, &edid_samus_gamma));
- EXPECT_DOUBLE_EQ(2.5, edid_samus_gamma);
-
- const std::vector<uint8_t> edid_eve(kEve, kEve + charsize(kEve));
- double edid_eve_gamma = 0.0;
- EXPECT_TRUE(ParseGammaValue(edid_eve, &edid_eve_gamma));
- EXPECT_DOUBLE_EQ(2.2, edid_eve_gamma);
-}
-
-TEST(EDIDParserTest, ParseBitsPerChannel) {
- const std::vector<uint8_t> edid_normal_display(
- kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- int edid_normal_display_bits_per_channel = 0;
- EXPECT_TRUE(ParseBitsPerChannel(edid_normal_display,
- &edid_normal_display_bits_per_channel));
- EXPECT_EQ(10, edid_normal_display_bits_per_channel);
-
- const std::vector<uint8_t> edid_internal_display(
- kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- int edid_internal_display_bits_per_channel = 0;
- // |kInternalDisplay| doesn't have bits per channel information.
- EXPECT_FALSE(ParseBitsPerChannel(edid_internal_display,
- &edid_internal_display_bits_per_channel));
-
- const std::vector<uint8_t> edid_hpz32x(kHPz32x, kHPz32x + charsize(kHPz32x));
- int edid_hpz32x_bits_per_channel = 0;
- EXPECT_TRUE(ParseBitsPerChannel(edid_hpz32x, &edid_hpz32x_bits_per_channel));
- EXPECT_EQ(10, edid_hpz32x_bits_per_channel);
-
- const std::vector<uint8_t> edid_samus(kSamus, kSamus + charsize(kSamus));
- int edid_samus_bits_per_channel = 0;
- EXPECT_TRUE(ParseBitsPerChannel(edid_samus, &edid_samus_bits_per_channel));
- EXPECT_EQ(8, edid_samus_bits_per_channel);
-
- const std::vector<uint8_t> edid_eve(kEve, kEve + charsize(kEve));
- int edid_eve_bits_per_channel = 0;
- EXPECT_TRUE(ParseBitsPerChannel(edid_eve, &edid_eve_bits_per_channel));
- EXPECT_EQ(8, edid_eve_bits_per_channel);
-}
+INSTANTIATE_TEST_CASE_P(, EDIDParserTest, ValuesIn(kTestCases));
} // namespace display
diff --git a/chromium/ui/display/util/fuzz_corpus/eve b/chromium/ui/display/util/fuzz_corpus/eve
new file mode 100644
index 00000000000..73cc2551931
--- /dev/null
+++ b/chromium/ui/display/util/fuzz_corpus/eve
Binary files differ
diff --git a/chromium/ui/display/util/fuzz_corpus/hpz32x b/chromium/ui/display/util/fuzz_corpus/hpz32x
new file mode 100644
index 00000000000..b7ee75d764f
--- /dev/null
+++ b/chromium/ui/display/util/fuzz_corpus/hpz32x
Binary files differ
diff --git a/chromium/ui/display/util/x11/edid_parser_x11.cc b/chromium/ui/display/util/x11/edid_parser_x11.cc
index 06edcf88c80..57baee9200c 100644
--- a/chromium/ui/display/util/x11/edid_parser_x11.cc
+++ b/chromium/ui/display/util/x11/edid_parser_x11.cc
@@ -73,33 +73,18 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
} // namespace
-EDIDParserX11::EDIDParserX11(XID output_id)
- : output_id_(output_id) {
+EDIDParserX11::EDIDParserX11(XID output_id) : output_id_(output_id) {
GetEDIDProperty(output_id_, &edid_);
}
-EDIDParserX11::~EDIDParserX11() {
-}
+EDIDParserX11::~EDIDParserX11() {}
bool EDIDParserX11::GetDisplayId(uint8_t index, int64_t* out_display_id) const {
if (edid_.empty())
return false;
- return GetDisplayIdFromEDID(edid_, index, out_display_id, nullptr);
-}
-
-std::string EDIDParserX11::GetDisplayName() const {
- std::string display_name;
- ParseOutputDeviceData(edid_, nullptr, nullptr, &display_name, nullptr,
- nullptr);
- return display_name;
-}
-
-bool EDIDParserX11::GetOutputOverscanFlag(bool* out_flag) const {
- if (edid_.empty())
- return false;
-
- return ParseOutputOverscanFlag(edid_, out_flag);
+ *out_display_id = EdidParser(edid_).GetDisplayId(output_id_);
+ return true;
}
} // namespace display
diff --git a/chromium/ui/display/util/x11/edid_parser_x11.h b/chromium/ui/display/util/x11/edid_parser_x11.h
index 0c49015b99f..383d828916f 100644
--- a/chromium/ui/display/util/x11/edid_parser_x11.h
+++ b/chromium/ui/display/util/x11/edid_parser_x11.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/util/display_util_export.h"
+#include "ui/display/util/edid_parser.h"
typedef unsigned long XID;
typedef XID RROutput;
@@ -31,22 +32,11 @@ class DISPLAY_UTIL_EXPORT EDIDParserX11 {
// Returns true if successful, false otherwise.
bool GetDisplayId(uint8_t index, int64_t* out_display_id) const;
- // Generate the human readable string from EDID obtained from |output|.
- // Returns an empty string upon error.
- std::string GetDisplayName() const;
-
- // Gets the overscan flag and stores to |out_flag|. Returns true if the flag
- // is found. Otherwise returns false and doesn't touch |out_flag|. The output
- // will produce overscan if |out_flag| is set to true, but the output may
- // still produce overscan even though it returns true and |out_flag| is set to
- // false.
- bool GetOutputOverscanFlag(bool* out_flag) const;
-
XID output_id() const { return output_id_; }
const std::vector<uint8_t>& edid() const { return edid_; }
private:
- XID output_id_;
+ const XID output_id_;
// This will be an empty vector upon failure to get the EDID from the
// |output_id_|.
diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn
index 96adf2efb72..d5bb88155d6 100644
--- a/chromium/ui/events/BUILD.gn
+++ b/chromium/ui/events/BUILD.gn
@@ -41,6 +41,12 @@ source_set("event_constants") {
]
}
+source_set("platform_event") {
+ sources = [
+ "platform_event.h",
+ ]
+}
+
component("events_base") {
sources = [
"android/scroller.cc",
@@ -80,6 +86,7 @@ component("events_base") {
public_deps = [
":dom_keycode_converter",
":event_constants",
+ ":platform_event",
"//base",
"//ui/events/platform",
"//ui/gfx/geometry",
@@ -352,13 +359,14 @@ static_library("test_support") {
libs = [ "Carbon.framework" ]
}
- if (use_x11) {
+ if (use_x11 || ozone_platform_x11) {
sources += [
"test/events_test_utils_x11.cc",
"test/events_test_utils_x11.h",
]
deps += [
"//ui/events/devices/x11",
+ "//ui/events/keycodes:x11",
"//ui/gfx/x",
]
}
@@ -376,6 +384,8 @@ if (!is_ios) {
"blink/fling_booster_unittest.cc",
"blink/input_handler_proxy_unittest.cc",
"blink/input_scroll_elasticity_controller_unittest.cc",
+ "blink/snap_fling_controller_unittest.cc",
+ "blink/snap_fling_curve_unittest.cc",
"blink/web_input_event_traits_unittest.cc",
"blink/web_input_event_unittest.cc",
"cocoa/events_mac_unittest.mm",
@@ -384,6 +394,7 @@ if (!is_ios) {
"event_dispatcher_unittest.cc",
"event_processor_unittest.cc",
"event_rewriter_unittest.cc",
+ "event_target_unittest.cc",
"event_unittest.cc",
"fraction_of_time_without_user_input_recorder_unittest.cc",
"gesture_detection/bitset_32_unittest.cc",
@@ -421,7 +432,7 @@ if (!is_ios) {
"//skia",
"//testing/gmock",
"//testing/gtest",
- "//third_party/WebKit/public:blink_headers",
+ "//third_party/blink/public:blink_headers",
"//ui/base:test_support",
"//ui/display",
"//ui/events/blink",
diff --git a/chromium/ui/events/base_event_utils.cc b/chromium/ui/events/base_event_utils.cc
index 20bbed9d18f..21dc226e9ff 100644
--- a/chromium/ui/events/base_event_utils.cc
+++ b/chromium/ui/events/base_event_utils.cc
@@ -47,7 +47,7 @@ bool IsSystemKeyModifier(int flags) {
(EF_ALTGR_DOWN & flags) == 0;
}
-base::LazyInstance<base::TickClock*>::Leaky g_tick_clock =
+base::LazyInstance<const base::TickClock*>::Leaky g_tick_clock =
LAZY_INSTANCE_INITIALIZER;
base::TimeTicks EventTimeForNow() {
@@ -55,7 +55,7 @@ base::TimeTicks EventTimeForNow() {
: base::TimeTicks::Now();
}
-void SetEventTickClockForTesting(base::TickClock* tick_clock) {
+void SetEventTickClockForTesting(const base::TickClock* tick_clock) {
g_tick_clock.Get() = tick_clock;
}
diff --git a/chromium/ui/events/base_event_utils.h b/chromium/ui/events/base_event_utils.h
index d030fd15b8d..c75509fd171 100644
--- a/chromium/ui/events/base_event_utils.h
+++ b/chromium/ui/events/base_event_utils.h
@@ -30,7 +30,7 @@ EVENTS_BASE_EXPORT base::TimeTicks EventTimeForNow();
// Overrides the clock used by EventTimeForNow for testing.
// This doesn't take the ownership of the clock.
EVENTS_BASE_EXPORT void SetEventTickClockForTesting(
- base::TickClock* tick_clock);
+ const base::TickClock* tick_clock);
// Converts an event timestamp ticks to seconds (floating point representation).
// WARNING: This should only be used when interfacing with platform code that
diff --git a/chromium/ui/events/blink/BUILD.gn b/chromium/ui/events/blink/BUILD.gn
index f22697697d5..0a93dd31201 100644
--- a/chromium/ui/events/blink/BUILD.gn
+++ b/chromium/ui/events/blink/BUILD.gn
@@ -24,6 +24,10 @@ jumbo_source_set("blink") {
"input_handler_proxy_client.h",
"input_scroll_elasticity_controller.cc",
"input_scroll_elasticity_controller.h",
+ "snap_fling_controller.cc",
+ "snap_fling_controller.h",
+ "snap_fling_curve.cc",
+ "snap_fling_curve.h",
"synchronous_input_handler_proxy.h",
"web_input_event.cc",
"web_input_event.h",
@@ -33,7 +37,7 @@ jumbo_source_set("blink") {
deps = [
"//cc:cc",
- "//third_party/WebKit/public:blink_headers",
+ "//third_party/blink/public:blink_headers",
"//ui/events",
"//ui/events:dom_keycode_converter",
"//ui/events:events_base",
diff --git a/chromium/ui/events/blink/DEPS b/chromium/ui/events/blink/DEPS
index b1228dde788..6df7edf0a39 100644
--- a/chromium/ui/events/blink/DEPS
+++ b/chromium/ui/events/blink/DEPS
@@ -5,17 +5,17 @@ include_rules = [
"+cc/input/scroll_elasticity_helper.h",
"+cc/trees/swap_promise_monitor.h",
- "+third_party/WebKit/public/platform/WebGestureCurve.h",
- "+third_party/WebKit/public/platform/WebGestureCurveTarget.h",
- "+third_party/WebKit/public/platform/WebFloatPoint.h",
- "+third_party/WebKit/public/platform/WebFloatSize.h",
- "+third_party/WebKit/public/platform/WebGestureEvent.h",
- "+third_party/WebKit/public/platform/WebInputEvent.h",
- "+third_party/WebKit/public/platform/WebKeyboardEvent.h",
- "+third_party/WebKit/public/platform/WebMouseWheelEvent.h",
- "+third_party/WebKit/public/platform/WebPoint.h",
- "+third_party/WebKit/public/platform/WebTouchEvent.h",
- "+third_party/WebKit/public/web/WebActiveFlingParameters.h",
+ "+third_party/blink/public/platform/web_gesture_curve.h",
+ "+third_party/blink/public/platform/web_gesture_curve_target.h",
+ "+third_party/blink/public/platform/web_float_point.h",
+ "+third_party/blink/public/platform/web_float_size.h",
+ "+third_party/blink/public/platform/web_gesture_event.h",
+ "+third_party/blink/public/platform/web_input_event.h",
+ "+third_party/blink/public/platform/web_keyboard_event.h",
+ "+third_party/blink/public/platform/web_mouse_wheel_event.h",
+ "+third_party/blink/public/platform/web_point.h",
+ "+third_party/blink/public/platform/web_touch_event.h",
+ "+third_party/blink/public/web/web_active_fling_parameters.h",
"+ui/display/win",
"+ui/gfx",
diff --git a/chromium/ui/events/blink/blink_event_util.cc b/chromium/ui/events/blink/blink_event_util.cc
index c8d058216b2..c0b30b60a43 100644
--- a/chromium/ui/events/blink/blink_event_util.cc
+++ b/chromium/ui/events/blink/blink_event_util.cc
@@ -13,8 +13,8 @@
#include "base/time/time.h"
#include "build/build_config.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
#include "ui/events/android/gesture_event_android.h"
#include "ui/events/android/gesture_event_type.h"
#include "ui/events/base_event_utils.h"
@@ -416,7 +416,7 @@ bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
const WebGestureEvent& event) {
if (event.GetType() != event_to_coalesce.GetType() ||
event.resending_plugin_id != event_to_coalesce.resending_plugin_id ||
- event.source_device != event_to_coalesce.source_device ||
+ event.SourceDevice() != event_to_coalesce.SourceDevice() ||
event.GetModifiers() != event_to_coalesce.GetModifiers())
return false;
@@ -426,7 +426,7 @@ bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
// GesturePinchUpdate scales can be combined only if they share a focal point,
// e.g., with double-tap drag zoom.
if (event.GetType() == WebInputEvent::kGesturePinchUpdate &&
- event.x == event_to_coalesce.x && event.y == event_to_coalesce.y)
+ event.PositionInWidget() == event_to_coalesce.PositionInWidget())
return true;
return false;
@@ -462,9 +462,11 @@ gfx::Transform GetTransformForEvent(const WebGestureEvent& gesture_event) {
gesture_event.data.scroll_update.delta_y);
} else if (gesture_event.GetType() == WebInputEvent::kGesturePinchUpdate) {
float scale = gesture_event.data.pinch_update.scale;
- gesture_transform.Translate(-gesture_event.x, -gesture_event.y);
+ gesture_transform.Translate(-gesture_event.PositionInWidget().x,
+ -gesture_event.PositionInWidget().y);
gesture_transform.Scale(scale, scale);
- gesture_transform.Translate(gesture_event.x, gesture_event.y);
+ gesture_transform.Translate(gesture_event.PositionInWidget().x,
+ gesture_event.PositionInWidget().y);
} else {
NOTREACHED() << "Invalid event type for transform retrieval: "
<< WebInputEvent::GetName(gesture_event.GetType());
@@ -545,7 +547,7 @@ bool IsCompatibleScrollorPinch(const WebGestureEvent& new_event,
return (event_in_queue.GetType() == WebInputEvent::kGestureScrollUpdate ||
event_in_queue.GetType() == WebInputEvent::kGesturePinchUpdate) &&
event_in_queue.GetModifiers() == new_event.GetModifiers() &&
- event_in_queue.source_device == new_event.source_device;
+ event_in_queue.SourceDevice() == new_event.SourceDevice();
}
std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch(
@@ -559,20 +561,17 @@ std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch(
DCHECK(!second_last_event ||
IsCompatibleScrollorPinch(new_event, *second_last_event));
- WebGestureEvent scroll_event(WebInputEvent::kGestureScrollUpdate,
- new_event.GetModifiers(),
- new_event.TimeStampSeconds());
+ WebGestureEvent scroll_event(
+ WebInputEvent::kGestureScrollUpdate, new_event.GetModifiers(),
+ new_event.TimeStampSeconds(), new_event.SourceDevice());
WebGestureEvent pinch_event;
- scroll_event.source_device = new_event.source_device;
scroll_event.primary_pointer_type = new_event.primary_pointer_type;
pinch_event = scroll_event;
pinch_event.SetType(WebInputEvent::kGesturePinchUpdate);
- pinch_event.x = new_event.GetType() == WebInputEvent::kGesturePinchUpdate
- ? new_event.x
- : last_event.x;
- pinch_event.y = new_event.GetType() == WebInputEvent::kGesturePinchUpdate
- ? new_event.y
- : last_event.y;
+ pinch_event.SetPositionInWidget(new_event.GetType() ==
+ WebInputEvent::kGesturePinchUpdate
+ ? new_event.PositionInWidget()
+ : last_event.PositionInWidget());
gfx::Transform combined_scroll_pinch = GetTransformForEvent(last_event);
if (second_last_event) {
@@ -588,11 +587,13 @@ std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch(
float combined_scroll_pinch_y =
SkMScalarToFloat(combined_scroll_pinch.matrix().get(1, 3));
scroll_event.data.scroll_update.delta_x =
- (combined_scroll_pinch_x + pinch_event.x) / combined_scale -
- pinch_event.x;
+ (combined_scroll_pinch_x + pinch_event.PositionInWidget().x) /
+ combined_scale -
+ pinch_event.PositionInWidget().x;
scroll_event.data.scroll_update.delta_y =
- (combined_scroll_pinch_y + pinch_event.y) / combined_scale -
- pinch_event.y;
+ (combined_scroll_pinch_y + pinch_event.PositionInWidget().y) /
+ combined_scale -
+ pinch_event.PositionInWidget().y;
pinch_event.data.pinch_update.scale = combined_scale;
return std::make_pair(scroll_event, pinch_event);
@@ -675,26 +676,24 @@ WebGestureEvent CreateWebGestureEvent(const GestureEventDetails& details,
const gfx::PointF& raw_location,
int flags,
uint32_t unique_touch_event_id) {
- WebGestureEvent gesture(WebInputEvent::kUndefined,
- EventFlagsToWebEventModifiers(flags),
- ui::EventTimeStampToSeconds(timestamp));
- gesture.x = gfx::ToFlooredInt(location.x());
- gesture.y = gfx::ToFlooredInt(location.y());
- gesture.global_x = gfx::ToFlooredInt(raw_location.x());
- gesture.global_y = gfx::ToFlooredInt(raw_location.y());
-
+ blink::WebGestureDevice source_device = blink::kWebGestureDeviceUninitialized;
switch (details.device_type()) {
case GestureDeviceType::DEVICE_TOUCHSCREEN:
- gesture.source_device = blink::kWebGestureDeviceTouchscreen;
+ source_device = blink::kWebGestureDeviceTouchscreen;
break;
case GestureDeviceType::DEVICE_TOUCHPAD:
- gesture.source_device = blink::kWebGestureDeviceTouchpad;
+ source_device = blink::kWebGestureDeviceTouchpad;
break;
case GestureDeviceType::DEVICE_UNKNOWN:
NOTREACHED() << "Unknown device type is not allowed";
- gesture.source_device = blink::kWebGestureDeviceUninitialized;
break;
}
+ WebGestureEvent gesture(
+ WebInputEvent::kUndefined, EventFlagsToWebEventModifiers(flags),
+ ui::EventTimeStampToSeconds(timestamp), source_device);
+
+ gesture.SetPositionInWidget(location);
+ gesture.SetPositionInScreen(raw_location);
gesture.is_source_touch_event_set_non_blocking =
details.is_source_touch_event_set_non_blocking();
@@ -866,10 +865,9 @@ std::unique_ptr<blink::WebInputEvent> TranslateAndScaleWebInputEvent(
blink::WebGestureEvent* gesture_event = new blink::WebGestureEvent;
scaled_event.reset(gesture_event);
*gesture_event = static_cast<const blink::WebGestureEvent&>(event);
- gesture_event->x += delta.x();
- gesture_event->y += delta.y();
- gesture_event->x *= scale;
- gesture_event->y *= scale;
+ gesture_event->SetPositionInWidget(blink::WebFloatPoint(
+ (gesture_event->PositionInWidget().x + delta.x()) * scale,
+ (gesture_event->PositionInWidget().y + delta.y()) * scale));
switch (gesture_event->GetType()) {
case blink::WebInputEvent::kGestureScrollUpdate:
if (gesture_event->data.scroll_update.delta_units !=
@@ -1179,12 +1177,21 @@ std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid(
case GESTURE_EVENT_TYPE_SCROLL_START:
event_type = WebInputEvent::kGestureScrollBegin;
break;
+ case GESTURE_EVENT_TYPE_SCROLL_BY:
+ event_type = WebInputEvent::kGestureScrollUpdate;
+ break;
+ case GESTURE_EVENT_TYPE_SCROLL_END:
+ event_type = WebInputEvent::kGestureScrollEnd;
+ break;
case GESTURE_EVENT_TYPE_FLING_START:
event_type = WebInputEvent::kGestureFlingStart;
break;
case GESTURE_EVENT_TYPE_FLING_CANCEL:
event_type = WebInputEvent::kGestureFlingCancel;
break;
+ case GESTURE_EVENT_TYPE_DOUBLE_TAP:
+ event_type = WebInputEvent::kGestureDoubleTap;
+ break;
default:
NOTREACHED() << "Unknown gesture event type";
return std::make_unique<WebGestureEvent>();
@@ -1194,19 +1201,20 @@ std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid(
// NOTE: Source gesture events are synthetic ones that simulate
// gesture from keyboard (zoom in/out) for now. Should populate Blink
// event's fields better when extended to handle more cases.
- web_event->x = event.location().x();
- web_event->y = event.location().y();
- web_event->global_x = event.screen_location().x();
- web_event->global_x = event.screen_location().y();
- web_event->source_device = blink::kWebGestureDeviceTouchscreen;
+ web_event->SetPositionInWidget(event.location());
+ web_event->SetPositionInScreen(event.screen_location());
+ web_event->SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
if (event.synthetic_scroll())
- web_event->source_device = blink::kWebGestureDeviceSyntheticAutoscroll;
+ web_event->SetSourceDevice(blink::kWebGestureDeviceSyntheticAutoscroll);
if (event_type == WebInputEvent::kGesturePinchUpdate) {
web_event->data.pinch_update.scale = event.scale();
} else if (event_type == WebInputEvent::kGestureScrollBegin) {
web_event->data.scroll_begin.delta_x_hint = event.delta_x();
web_event->data.scroll_begin.delta_y_hint = event.delta_y();
web_event->data.scroll_begin.target_viewport = event.target_viewport();
+ } else if (event_type == WebInputEvent::kGestureScrollUpdate) {
+ web_event->data.scroll_update.delta_x = event.delta_x();
+ web_event->data.scroll_update.delta_y = event.delta_y();
} else if (event_type == WebInputEvent::kGestureFlingStart) {
web_event->data.fling_start.velocity_x = event.velocity_x();
web_event->data.fling_start.velocity_y = event.velocity_y();
@@ -1215,6 +1223,11 @@ std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid(
web_event->data.fling_cancel.prevent_boosting = true;
if (event.synthetic_scroll())
web_event->data.fling_cancel.target_viewport = true;
+ } else if (event_type == WebInputEvent::kGestureDoubleTap) {
+ // Set the tap count to 1 even for DoubleTap, in order to be consistent with
+ // double tap behavior on a mobile viewport. See https://crbug.com/234986
+ // for context.
+ web_event->data.tap.tap_count = 1;
}
return web_event;
diff --git a/chromium/ui/events/blink/blink_event_util.h b/chromium/ui/events/blink/blink_event_util.h
index 24b85de5204..6678fcfb481 100644
--- a/chromium/ui/events/blink/blink_event_util.h
+++ b/chromium/ui/events/blink/blink_event_util.h
@@ -8,9 +8,9 @@
#include <memory>
#include "build/build_config.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
#include "ui/events/event_constants.h"
#include "ui/events/gesture_detection/motion_event.h"
diff --git a/chromium/ui/events/blink/blink_event_util_unittest.cc b/chromium/ui/events/blink/blink_event_util_unittest.cc
index b8cb09a9f16..99c87370eed 100644
--- a/chromium/ui/events/blink/blink_event_util_unittest.cc
+++ b/chromium/ui/events/blink/blink_event_util_unittest.cc
@@ -6,9 +6,9 @@
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
#include "ui/events/gesture_event_details.h"
namespace ui {
diff --git a/chromium/ui/events/blink/compositor_thread_event_queue.cc b/chromium/ui/events/blink/compositor_thread_event_queue.cc
index 63c2386a045..d2796793b49 100644
--- a/chromium/ui/events/blink/compositor_thread_event_queue.cc
+++ b/chromium/ui/events/blink/compositor_thread_event_queue.cc
@@ -4,7 +4,6 @@
#include "ui/events/blink/compositor_thread_event_queue.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/web_input_event_traits.h"
diff --git a/chromium/ui/events/blink/event_with_callback.cc b/chromium/ui/events/blink/event_with_callback.cc
index a3e0b210be7..1e23768b0d3 100644
--- a/chromium/ui/events/blink/event_with_callback.cc
+++ b/chromium/ui/events/blink/event_with_callback.cc
@@ -4,7 +4,6 @@
#include "ui/events/blink/event_with_callback.h"
-#include "base/memory/ptr_util.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/did_overscroll_params.h"
#include "ui/events/blink/web_input_event_traits.h"
diff --git a/chromium/ui/events/blink/fling_booster.cc b/chromium/ui/events/blink/fling_booster.cc
index 233d7204c4d..c1f621c3837 100644
--- a/chromium/ui/events/blink/fling_booster.cc
+++ b/chromium/ui/events/blink/fling_booster.cc
@@ -59,7 +59,7 @@ bool FlingBooster::FilterGestureEventForFlingBoosting(
return false;
// Gestures from a different source should immediately interrupt the fling.
- if (gesture_event.source_device != source_device_) {
+ if (gesture_event.SourceDevice() != source_device_) {
*out_cancel_current_fling = true;
return false;
}
@@ -100,7 +100,7 @@ bool FlingBooster::FilterGestureEventForFlingBoosting(
return true;
case WebInputEvent::kGestureFlingStart: {
- DCHECK_EQ(source_device_, gesture_event.source_device);
+ DCHECK_EQ(source_device_, gesture_event.SourceDevice());
gfx::Vector2dF new_fling_velocity(
gesture_event.data.fling_start.velocity_x,
gesture_event.data.fling_start.velocity_y);
diff --git a/chromium/ui/events/blink/fling_booster.h b/chromium/ui/events/blink/fling_booster.h
index 50e5c2b41f8..f1bbf959971 100644
--- a/chromium/ui/events/blink/fling_booster.h
+++ b/chromium/ui/events/blink/fling_booster.h
@@ -5,7 +5,7 @@
#ifndef UI_EVENTS_BLINK_FLING_BOOSTER_H_
#define UI_EVENTS_BLINK_FLING_BOOSTER_H_
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
namespace ui {
diff --git a/chromium/ui/events/blink/fling_booster_unittest.cc b/chromium/ui/events/blink/fling_booster_unittest.cc
index 075363552fb..9a70b41234a 100644
--- a/chromium/ui/events/blink/fling_booster_unittest.cc
+++ b/chromium/ui/events/blink/fling_booster_unittest.cc
@@ -21,7 +21,7 @@ namespace test {
class FlingBoosterTest : public testing::Test {
public:
FlingBoosterTest() : delta_time_(base::TimeDelta::FromMilliseconds(10)) {
- gesture_scroll_event_.source_device = blink::kWebGestureDeviceTouchscreen;
+ gesture_scroll_event_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
}
WebGestureEvent CreateFlingStart(base::TimeTicks timestamp,
@@ -29,8 +29,8 @@ class FlingBoosterTest : public testing::Test {
const gfx::Vector2dF& velocity,
int modifiers) {
WebGestureEvent fling_start(WebInputEvent::kGestureFlingStart, modifiers,
- EventTimeStampToSeconds(timestamp));
- fling_start.source_device = source_device;
+ EventTimeStampToSeconds(timestamp),
+ source_device);
fling_start.data.fling_start.velocity_x = velocity.x();
fling_start.data.fling_start.velocity_y = velocity.y();
return fling_start;
@@ -39,8 +39,8 @@ class FlingBoosterTest : public testing::Test {
WebGestureEvent CreateFlingCancel(base::TimeTicks timestamp,
WebGestureDevice source_device) {
WebGestureEvent fling_cancel(WebInputEvent::kGestureFlingCancel, 0,
- EventTimeStampToSeconds(timestamp));
- fling_cancel.source_device = source_device;
+ EventTimeStampToSeconds(timestamp),
+ source_device);
return fling_cancel;
}
diff --git a/chromium/ui/events/blink/input_handler_proxy.cc b/chromium/ui/events/blink/input_handler_proxy.cc
index 6d77910839f..0ae50266b88 100644
--- a/chromium/ui/events/blink/input_handler_proxy.cc
+++ b/chromium/ui/events/blink/input_handler_proxy.cc
@@ -12,16 +12,15 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
#include "cc/input/main_thread_scrolling_reason.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/compositor_thread_event_queue.h"
#include "ui/events/blink/did_overscroll_params.h"
@@ -78,8 +77,8 @@ cc::ScrollState CreateScrollStateForGesture(const WebGestureEvent& event) {
cc::ScrollStateData scroll_state_data;
switch (event.GetType()) {
case WebInputEvent::kGestureScrollBegin:
- scroll_state_data.position_x = event.x;
- scroll_state_data.position_y = event.y;
+ scroll_state_data.position_x = event.PositionInWidget().x;
+ scroll_state_data.position_y = event.PositionInWidget().y;
scroll_state_data.delta_x_hint = -event.data.scroll_begin.delta_x_hint;
scroll_state_data.delta_y_hint = -event.data.scroll_begin.delta_y_hint;
scroll_state_data.is_beginning = true;
@@ -114,6 +113,21 @@ cc::ScrollState CreateScrollStateForGesture(const WebGestureEvent& event) {
return cc::ScrollState(scroll_state_data);
}
+cc::ScrollState CreateScrollStateForInertialEnd() {
+ cc::ScrollStateData scroll_state_data;
+ scroll_state_data.is_ending = true;
+ return cc::ScrollState(scroll_state_data);
+}
+
+cc::ScrollState CreateScrollStateForInertialUpdate(
+ const gfx::Vector2dF& delta) {
+ cc::ScrollStateData scroll_state_data;
+ scroll_state_data.delta_x = delta.x();
+ scroll_state_data.delta_y = delta.y();
+ scroll_state_data.is_in_inertial_phase = true;
+ return cc::ScrollState(scroll_state_data);
+}
+
cc::InputHandler::ScrollInputType GestureScrollInputType(
blink::WebGestureDevice device) {
return device == blink::kWebGestureDeviceTouchpad
@@ -161,7 +175,8 @@ InputHandlerProxy::InputHandlerProxy(
current_overscroll_params_(nullptr),
has_ongoing_compositor_scroll_fling_pinch_(false),
is_first_gesture_scroll_update_(false),
- tick_clock_(base::DefaultTickClock::GetInstance()) {
+ tick_clock_(base::DefaultTickClock::GetInstance()),
+ snap_fling_controller_(std::make_unique<SnapFlingController>(this)) {
DCHECK(client);
input_handler_->BindToClient(this,
touchpad_and_wheel_scroll_latching_enabled_);
@@ -214,13 +229,13 @@ void InputHandlerProxy::HandleInputEventWithLatencyInfo(
if (has_ongoing_compositor_scroll_fling_pinch_) {
const auto& gesture_event = ToWebGestureEvent(event_with_callback->event());
bool is_from_set_non_blocking_touch =
- gesture_event.source_device == blink::kWebGestureDeviceTouchscreen &&
+ gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchscreen &&
gesture_event.is_source_touch_event_set_non_blocking;
bool is_scroll_end_from_wheel =
- gesture_event.source_device == blink::kWebGestureDeviceTouchpad &&
+ gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad &&
gesture_event.GetType() == blink::WebGestureEvent::kGestureScrollEnd;
bool scroll_update_has_blocking_wheel_source =
- gesture_event.source_device == blink::kWebGestureDeviceTouchpad &&
+ gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad &&
gesture_event.GetType() ==
blink::WebGestureEvent::kGestureScrollUpdate &&
(!async_wheel_events_enabled_ || is_first_gesture_scroll_update_);
@@ -364,8 +379,8 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
DCHECK(fling_booster_->fling_cancellation_is_deferred());
TRACE_EVENT_INSTANT0("input", "InputHandlerProxy::FlingBoostStart",
TRACE_EVENT_SCOPE_THREAD);
- } else if (WebInputEvent::kGestureScrollBegin ||
- WebInputEvent::kGestureScrollUpdate) {
+ } else if (event.GetType() == WebInputEvent::kGestureScrollBegin ||
+ event.GetType() == WebInputEvent::kGestureScrollUpdate) {
TRACE_EVENT_INSTANT0("input",
"InputHandlerProxy::ExtendBoostedFlingTimeout",
TRACE_EVENT_SCOPE_THREAD);
@@ -375,6 +390,9 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
}
}
+ if (snap_fling_controller_->FilterEventForSnap(event))
+ return DROP_EVENT;
+
switch (event.GetType()) {
case WebInputEvent::kMouseWheel:
return HandleMouseWheel(static_cast<const WebMouseWheelEvent&>(event));
@@ -394,7 +412,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
DCHECK(!gesture_pinch_on_impl_thread_);
const WebGestureEvent& gesture_event =
static_cast<const WebGestureEvent&>(event);
- if (gesture_event.source_device == blink::kWebGestureDeviceTouchpad &&
+ if (gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad &&
input_handler_->GetEventListenerProperties(
cc::EventListenerClass::kMouseWheel) !=
cc::EventListenerProperties::kNone) {
@@ -412,8 +430,8 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
const WebGestureEvent& gesture_event =
static_cast<const WebGestureEvent&>(event);
input_handler_->PinchGestureEnd(
- gfx::Point(gesture_event.x, gesture_event.y),
- gesture_event.source_device == blink::kWebGestureDeviceTouchpad);
+ gfx::ToFlooredPoint(gesture_event.PositionInWidget()),
+ gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad);
return DID_HANDLE;
} else {
return DID_NOT_HANDLE;
@@ -427,7 +445,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent(
return DROP_EVENT;
input_handler_->PinchGestureUpdate(
gesture_event.data.pinch_update.scale,
- gfx::Point(gesture_event.x, gesture_event.y));
+ gfx::ToFlooredPoint(gesture_event.PositionInWidget()));
return DID_HANDLE;
} else {
return DID_NOT_HANDLE;
@@ -686,29 +704,33 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
cc::MainThreadScrollingReason::kContinuingMainThreadScroll;
} else if (gesture_event.data.scroll_begin.target_viewport) {
scroll_status = input_handler_->RootScrollBegin(
- &scroll_state, GestureScrollInputType(gesture_event.source_device));
+ &scroll_state, GestureScrollInputType(gesture_event.SourceDevice()));
} else if (ShouldAnimate(gesture_event.data.scroll_begin.delta_hint_units !=
blink::WebGestureEvent::ScrollUnits::kPixels)) {
DCHECK(!scroll_state.is_in_inertial_phase());
scroll_status = input_handler_->ScrollAnimatedBegin(&scroll_state);
} else {
scroll_status = input_handler_->ScrollBegin(
- &scroll_state, GestureScrollInputType(gesture_event.source_device));
+ &scroll_state, GestureScrollInputType(gesture_event.SourceDevice()));
}
- RecordMainThreadScrollingReasons(gesture_event.source_device,
+ RecordMainThreadScrollingReasons(gesture_event.SourceDevice(),
scroll_status.main_thread_scrolling_reasons);
- RecordScrollingThreadStatus(gesture_event.source_device,
+ RecordScrollingThreadStatus(gesture_event.SourceDevice(),
scroll_status.main_thread_scrolling_reasons);
InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE;
scroll_sequence_ignored_ = false;
+ in_inertial_scrolling_ = false;
switch (scroll_status.thread) {
case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
TRACE_EVENT_INSTANT0("input",
"InputHandlerProxy::handle_input gesture scroll",
TRACE_EVENT_SCOPE_THREAD);
gesture_scroll_on_impl_thread_ = true;
+ if (input_handler_->IsCurrentlyScrollingViewport())
+ client_->DidStartScrollingViewport();
+
if (scroll_status.bubble)
result = DID_HANDLE_SHOULD_BUBBLE;
else
@@ -750,7 +772,8 @@ InputHandlerProxy::HandleGestureScrollUpdate(
return DID_NOT_HANDLE;
cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event);
- gfx::Point scroll_point(gesture_event.x, gesture_event.y);
+ in_inertial_scrolling_ = scroll_state.is_in_inertial_phase();
+ gfx::PointF scroll_point(gesture_event.PositionInWidget());
if (ShouldAnimate(gesture_event.data.scroll_update.delta_units !=
blink::WebGestureEvent::ScrollUnits::kPixels)) {
@@ -759,7 +782,9 @@ InputHandlerProxy::HandleGestureScrollUpdate(
base::TimeTicks() +
base::TimeDelta::FromSecondsD(gesture_event.TimeStampSeconds());
base::TimeDelta delay = base::TimeTicks::Now() - event_time;
- switch (input_handler_->ScrollAnimated(scroll_point, scroll_delta, delay)
+ switch (input_handler_
+ ->ScrollAnimated(gfx::ToFlooredPoint(scroll_point),
+ scroll_delta, delay)
.thread) {
case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
return DID_HANDLE;
@@ -774,14 +799,23 @@ InputHandlerProxy::HandleGestureScrollUpdate(
return DID_NOT_HANDLE;
}
}
+
+ if (snap_fling_controller_->HandleGestureScrollUpdate(gesture_event)) {
+#ifndef NDEBUG
+ expect_scroll_update_end_ = false;
+#endif
+ gesture_scroll_on_impl_thread_ = false;
+ return DROP_EVENT;
+ }
+
cc::InputHandlerScrollResult scroll_result =
input_handler_->ScrollBy(&scroll_state);
if (!scroll_result.did_scroll &&
input_handler_->ScrollingShouldSwitchtoMainThread() &&
- ((gesture_event.source_device == blink::kWebGestureDeviceTouchpad &&
+ ((gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad &&
touchpad_and_wheel_scroll_latching_enabled_) ||
- gesture_event.source_device == blink::kWebGestureDeviceTouchscreen)) {
+ gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchscreen)) {
gesture_scroll_on_impl_thread_ = false;
client_->GenerateScrollBeginAndSendToMainThread(gesture_event);
@@ -828,8 +862,9 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollEnd(
InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
const WebGestureEvent& gesture_event) {
- // Touchpad flings are handled on browser.
- DCHECK(!(gesture_event.source_device == blink::kWebGestureDeviceTouchpad));
+ // Touchpad and touchscreen flings are handled on browser.
+ DCHECK_NE(blink::kWebGestureDeviceTouchpad, gesture_event.SourceDevice());
+ DCHECK_NE(blink::kWebGestureDeviceTouchscreen, gesture_event.SourceDevice());
#ifndef NDEBUG
expect_scroll_update_end_ = false;
#endif
@@ -841,8 +876,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
cc::InputHandler::ScrollStatus scroll_status;
scroll_status.main_thread_scrolling_reasons =
cc::MainThreadScrollingReason::kNotScrollingOnMain;
- switch (gesture_event.source_device) {
- case blink::kWebGestureDeviceTouchscreen:
+ switch (gesture_event.SourceDevice()) {
case blink::kWebGestureDeviceSyntheticAutoscroll:
if (!gesture_scroll_on_impl_thread_) {
scroll_status.thread = cc::InputHandler::SCROLL_ON_MAIN_THREAD;
@@ -852,6 +886,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
scroll_status = input_handler_->FlingScrollBegin();
}
break;
+ case blink::kWebGestureDeviceTouchscreen:
case blink::kWebGestureDeviceTouchpad:
case blink::kWebGestureDeviceUninitialized:
case blink::kWebGestureDeviceCount:
@@ -989,9 +1024,9 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchStart(
result = DID_HANDLE_NON_BLOCKING;
}
- bool is_flinging_on_impl =
- fling_curve_ && !fling_may_be_active_on_main_thread_;
- if (is_flinging_on_impl && is_touching_scrolling_layer)
+ bool is_in_inertial_scrolling_on_impl =
+ in_inertial_scrolling_ && gesture_scroll_on_impl_thread_;
+ if (is_in_inertial_scrolling_on_impl && is_touching_scrolling_layer)
result = DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING;
client_->SetWhiteListedTouchAction(white_listed_touch_action,
@@ -1033,6 +1068,8 @@ void InputHandlerProxy::Animate(base::TimeTicks time) {
if (scroll_elasticity_controller_)
scroll_elasticity_controller_->Animate(time);
+ snap_fling_controller_->Animate(time);
+
if (!fling_curve_)
return;
@@ -1138,8 +1175,36 @@ void InputHandlerProxy::SynchronouslyZoomBy(float magnify_delta,
input_handler_->PinchGestureEnd(anchor, false);
}
+bool InputHandlerProxy::GetSnapFlingInfo(
+ const gfx::Vector2dF& natural_displacement,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const {
+ return input_handler_->GetSnapFlingInfo(natural_displacement, initial_offset,
+ target_offset);
+}
+
+gfx::Vector2dF InputHandlerProxy::ScrollByForSnapFling(
+ const gfx::Vector2dF& delta) {
+ cc::ScrollState scroll_state = CreateScrollStateForInertialUpdate(delta);
+ // TODO(sunyunjia): We should consider moving the scroll to main, handling
+ // overscroll, and handling elastic scroll after ScrollBy().
+ // https://crbug.com/819855
+ cc::InputHandlerScrollResult scroll_result =
+ input_handler_->ScrollBy(&scroll_state);
+ return scroll_result.current_offset;
+}
+
+void InputHandlerProxy::ScrollEndForSnapFling() {
+ cc::ScrollState scroll_state = CreateScrollStateForInertialEnd();
+ input_handler_->ScrollEnd(&scroll_state, false);
+}
+
+void InputHandlerProxy::RequestAnimationForSnapFling() {
+ RequestAnimation();
+}
+
void InputHandlerProxy::HandleOverscroll(
- const gfx::Point& causal_event_viewport_point,
+ const gfx::PointF& causal_event_viewport_point,
const cc::InputHandlerScrollResult& scroll_result,
bool bundle_overscroll_params_with_ack) {
DCHECK(client_);
@@ -1173,7 +1238,7 @@ void InputHandlerProxy::HandleOverscroll(
current_overscroll_params_->current_fling_velocity =
ToClientScrollIncrement(current_fling_velocity_);
current_overscroll_params_->causal_event_viewport_point =
- gfx::PointF(causal_event_viewport_point);
+ causal_event_viewport_point;
current_overscroll_params_->overscroll_behavior =
scroll_result.overscroll_behavior;
return;
@@ -1182,7 +1247,7 @@ void InputHandlerProxy::HandleOverscroll(
client_->DidOverscroll(scroll_result.accumulated_root_overscroll,
scroll_result.unused_scroll_delta,
ToClientScrollIncrement(current_fling_velocity_),
- gfx::PointF(causal_event_viewport_point),
+ causal_event_viewport_point,
scroll_result.overscroll_behavior);
}
@@ -1283,7 +1348,6 @@ bool InputHandlerProxy::ScrollBy(const WebFloatSize& increment,
bool did_scroll = false;
switch (fling_parameters_.source_device) {
- case blink::kWebGestureDeviceTouchscreen:
case blink::kWebGestureDeviceSyntheticAutoscroll: {
clipped_increment = ToClientScrollIncrement(clipped_increment);
cc::ScrollStateData scroll_state_data;
@@ -1298,6 +1362,7 @@ bool InputHandlerProxy::ScrollBy(const WebFloatSize& increment,
HandleOverscroll(fling_parameters_.point, scroll_result, false);
did_scroll = scroll_result.did_scroll;
} break;
+ case blink::kWebGestureDeviceTouchscreen:
case blink::kWebGestureDeviceTouchpad:
case blink::kWebGestureDeviceUninitialized:
case blink::kWebGestureDeviceCount:
@@ -1330,12 +1395,14 @@ void InputHandlerProxy::HandleScrollElasticityOverscroll(
// impl thread event handling paths.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&InputScrollElasticityController::ObserveGestureEventAndResult,
- scroll_elasticity_controller_->GetWeakPtr(), gesture_event,
- scroll_result));
+ base::BindOnce(
+ &InputScrollElasticityController::ObserveGestureEventAndResult,
+ scroll_elasticity_controller_->GetWeakPtr(), gesture_event,
+ scroll_result));
}
-void InputHandlerProxy::SetTickClockForTesting(base::TickClock* tick_clock) {
+void InputHandlerProxy::SetTickClockForTesting(
+ const base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
}
@@ -1343,23 +1410,22 @@ void InputHandlerProxy::UpdateCurrentFlingState(
const WebGestureEvent& fling_start_event,
const gfx::Vector2dF& velocity) {
DCHECK_EQ(WebInputEvent::kGestureFlingStart, fling_start_event.GetType());
- // When wheel scroll latching is enabled touchpad flings are handled on
- // browser.
- DCHECK(fling_start_event.source_device != blink::kWebGestureDeviceTouchpad ||
- !touchpad_and_wheel_scroll_latching_enabled_);
+ // Flings with touchpad and touchscreen source devices are handled on browser.
+ DCHECK(fling_start_event.SourceDevice() != blink::kWebGestureDeviceTouchpad &&
+ fling_start_event.SourceDevice() !=
+ blink::kWebGestureDeviceTouchscreen);
current_fling_velocity_ = velocity;
fling_curve_ = client_->CreateFlingAnimationCurve(
- fling_start_event.source_device,
+ fling_start_event.SourceDevice(),
WebFloatPoint(velocity.x(), velocity.y()), blink::WebSize());
disallow_horizontal_fling_scroll_ = !velocity.x();
disallow_vertical_fling_scroll_ = !velocity.y();
fling_parameters_.start_time = fling_start_event.TimeStampSeconds();
fling_parameters_.delta = WebFloatPoint(velocity.x(), velocity.y());
- fling_parameters_.point = WebPoint(fling_start_event.x, fling_start_event.y);
- fling_parameters_.global_point =
- WebPoint(fling_start_event.global_x, fling_start_event.global_y);
+ fling_parameters_.point = fling_start_event.PositionInWidget();
+ fling_parameters_.global_point = fling_start_event.PositionInScreen();
fling_parameters_.modifiers = fling_start_event.GetModifiers();
- fling_parameters_.source_device = fling_start_event.source_device;
+ fling_parameters_.source_device = fling_start_event.SourceDevice();
}
} // namespace ui
diff --git a/chromium/ui/events/blink/input_handler_proxy.h b/chromium/ui/events/blink/input_handler_proxy.h
index feeea9d1c65..0670562fa1f 100644
--- a/chromium/ui/events/blink/input_handler_proxy.h
+++ b/chromium/ui/events/blink/input_handler_proxy.h
@@ -10,12 +10,13 @@
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "cc/input/input_handler.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/web/WebActiveFlingParameters.h"
+#include "third_party/blink/public/platform/web_gesture_curve.h"
+#include "third_party/blink/public/platform/web_gesture_curve_target.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/web/web_active_fling_parameters.h"
#include "ui/events/blink/blink_features.h"
#include "ui/events/blink/input_scroll_elasticity_controller.h"
+#include "ui/events/blink/snap_fling_controller.h"
#include "ui/events/blink/synchronous_input_handler_proxy.h"
#include "ui/events/blink/web_input_event_traits.h"
@@ -51,7 +52,8 @@ struct DidOverscrollParams;
// events intended for a specific WebWidget.
class InputHandlerProxy : public cc::InputHandlerClient,
public SynchronousInputHandlerProxy,
- public blink::WebGestureCurveTarget {
+ public blink::WebGestureCurveTarget,
+ public SnapFlingClient {
public:
InputHandlerProxy(cc::InputHandler* input_handler,
InputHandlerProxyClient* client,
@@ -114,6 +116,14 @@ class InputHandlerProxy : public cc::InputHandlerClient,
bool ScrollBy(const blink::WebFloatSize& offset,
const blink::WebFloatSize& velocity) override;
+ // SnapFlingClient implementation.
+ bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const override;
+ gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) override;
+ void ScrollEndForSnapFling() override;
+ void RequestAnimationForSnapFling() override;
+
bool gesture_scroll_on_impl_thread_for_testing() const {
return gesture_scroll_on_impl_thread_;
}
@@ -164,7 +174,7 @@ class InputHandlerProxy : public cc::InputHandlerClient,
// Used to send overscroll messages to the browser.
// |bundle_overscroll_params_with_ack| means overscroll message should be
// bundled with triggering event response, and won't fire |DidOverscroll|.
- void HandleOverscroll(const gfx::Point& causal_event_viewport_point,
+ void HandleOverscroll(const gfx::PointF& causal_event_viewport_point,
const cc::InputHandlerScrollResult& scroll_result,
bool bundle_overscroll_params_with_ack);
@@ -179,7 +189,7 @@ class InputHandlerProxy : public cc::InputHandlerClient,
// Overrides the internal clock for testing.
// This doesn't take the ownership of the clock. |tick_clock| must outlive the
// InputHandlerProxy instance.
- void SetTickClockForTesting(base::TickClock* tick_clock);
+ void SetTickClockForTesting(const base::TickClock* tick_clock);
// |is_touching_scrolling_layer| indicates if one of the points that has
// been touched hits a currently scrolling layer.
@@ -213,6 +223,7 @@ class InputHandlerProxy : public cc::InputHandlerClient,
#endif
bool gesture_scroll_on_impl_thread_;
bool gesture_pinch_on_impl_thread_;
+ bool in_inertial_scrolling_ = false;
bool scroll_sequence_ignored_;
// This is always false when there are no flings on the main thread, but
// conservative in the sense that we might not be actually flinging when it is
@@ -260,10 +271,12 @@ class InputHandlerProxy : public cc::InputHandlerClient,
bool has_ongoing_compositor_scroll_fling_pinch_;
bool is_first_gesture_scroll_update_;
- base::TickClock* tick_clock_;
+ const base::TickClock* tick_clock_;
std::unique_ptr<FlingBooster> fling_booster_;
+ std::unique_ptr<SnapFlingController> snap_fling_controller_;
+
DISALLOW_COPY_AND_ASSIGN(InputHandlerProxy);
};
diff --git a/chromium/ui/events/blink/input_handler_proxy_client.h b/chromium/ui/events/blink/input_handler_proxy_client.h
index 3d992cd12fb..d6d44c93df1 100644
--- a/chromium/ui/events/blink/input_handler_proxy_client.h
+++ b/chromium/ui/events/blink/input_handler_proxy_client.h
@@ -49,6 +49,8 @@ class InputHandlerProxyClient {
virtual void DidAnimateForInput() = 0;
+ virtual void DidStartScrollingViewport() = 0;
+
// Used to send a GSB to the main thread when the wheel scroll latching is
// enabled and the scrolling should switch to the main thread.
virtual void GenerateScrollBeginAndSendToMainThread(
diff --git a/chromium/ui/events/blink/input_handler_proxy_unittest.cc b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
index 2f1830b4735..0d890a51654 100644
--- a/chromium/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
@@ -18,14 +18,14 @@
#include "cc/trees/swap_promise_monitor.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebFloatPoint.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
-#include "third_party/WebKit/public/platform/WebPoint.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_float_point.h"
+#include "third_party/blink/public/platform/web_float_size.h"
+#include "third_party/blink/public/platform/web_gesture_curve.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_keyboard_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_point.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/compositor_thread_event_queue.h"
#include "ui/events/blink/did_overscroll_params.h"
@@ -85,32 +85,21 @@ MATCHER_P(WheelEventsMatch, expected, "") {
WebGestureEvent CreateFling(base::TimeTicks timestamp,
WebGestureDevice source_device,
WebFloatPoint velocity,
- WebPoint point,
- WebPoint global_point,
+ WebFloatPoint point,
+ WebFloatPoint global_point,
int modifiers) {
WebGestureEvent fling(WebInputEvent::kGestureFlingStart, modifiers,
- (timestamp - base::TimeTicks()).InSecondsF());
+ (timestamp - base::TimeTicks()).InSecondsF(),
+ source_device);
// Touchpad fling is handled on broswer.
DCHECK(source_device != blink::kWebGestureDeviceTouchpad);
- fling.source_device = source_device;
fling.data.fling_start.velocity_x = velocity.x;
fling.data.fling_start.velocity_y = velocity.y;
- fling.x = point.x;
- fling.y = point.y;
- fling.global_x = global_point.x;
- fling.global_y = global_point.y;
+ fling.SetPositionInWidget(point);
+ fling.SetPositionInScreen(global_point);
return fling;
}
-WebGestureEvent CreateFling(WebGestureDevice source_device,
- WebFloatPoint velocity,
- WebPoint point,
- WebPoint global_point,
- int modifiers) {
- return CreateFling(base::TimeTicks(), source_device, velocity, point,
- global_point, modifiers);
-}
-
WebScopedInputEvent CreateGestureScrollFlingPinch(
WebInputEvent::Type type,
WebGestureDevice source_device,
@@ -118,8 +107,8 @@ WebScopedInputEvent CreateGestureScrollFlingPinch(
int x = 0,
int y = 0) {
WebGestureEvent gesture(type, WebInputEvent::kNoModifiers,
- WebInputEvent::GetStaticTimeStampForTests());
- gesture.source_device = source_device;
+ WebInputEvent::GetStaticTimeStampForTests(),
+ source_device);
if (type == WebInputEvent::kGestureScrollUpdate) {
gesture.data.scroll_update.delta_y = delta_y_or_scale;
} else if (type == WebInputEvent::kGestureFlingStart) {
@@ -128,8 +117,7 @@ WebScopedInputEvent CreateGestureScrollFlingPinch(
gesture.data.fling_start.velocity_y = delta_y_or_scale;
} else if (type == WebInputEvent::kGesturePinchUpdate) {
gesture.data.pinch_update.scale = delta_y_or_scale;
- gesture.x = x;
- gesture.y = y;
+ gesture.SetPositionInWidget(gfx::PointF(x, y));
}
return WebInputEventTraits::Clone(gesture);
}
@@ -208,6 +196,11 @@ class MockInputHandler : public cc::InputHandler {
}
void set_is_scrolling_root(bool is) { is_scrolling_root_ = is; }
+ MOCK_CONST_METHOD3(GetSnapFlingInfo,
+ bool(const gfx::Vector2dF& natural_displacement,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset));
+
private:
bool is_scrolling_root_ = true;
DISALLOW_COPY_AND_ASSIGN(MockInputHandler);
@@ -293,6 +286,7 @@ class MockInputHandlerProxyClient
const cc::OverscrollBehavior& overscroll_behavior));
void DidStopFlinging() override {}
void DidAnimateForInput() override {}
+ void DidStartScrollingViewport() override {}
MOCK_METHOD3(SetWhiteListedTouchAction,
void(cc::TouchAction touch_action,
uint32_t unique_touch_event_id,
@@ -393,7 +387,7 @@ class InputHandlerProxyTest
mock_input_handler_.set_is_scrolling_root(synchronous_root_scroll_);
// Set a default device so tests don't always have to set this.
- gesture_.source_device = blink::kWebGestureDeviceTouchpad;
+ gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchpad);
}
virtual ~InputHandlerProxyTest() { input_handler_.reset(); }
@@ -436,14 +430,14 @@ class InputHandlerProxyTest
void StartFling(base::TimeTicks timestamp,
WebGestureDevice source_device,
WebFloatPoint velocity,
- WebPoint position) {
+ WebFloatPoint position) {
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(kImplThreadScrollState));
gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = source_device;
+ gesture_.SetSourceDevice(source_device);
EXPECT_EQ(expected_disposition_,
input_handler_->HandleInputEvent(gesture_));
@@ -482,6 +476,7 @@ class InputHandlerProxyTest
void GestureScrollStarted();
void ScrollHandlingSwitchedToMainThread();
void GestureScrollIgnored();
+ void FlingAndSnap();
const bool synchronous_root_scroll_;
const bool install_synchronous_handler_;
@@ -545,7 +540,7 @@ class InputHandlerProxyEventQueueTest : public testing::TestWithParam<bool> {
CreateGestureScrollFlingPinch(type, source_device, delta_y_or_scale, x,
y),
latency,
- base::Bind(
+ base::BindOnce(
&InputHandlerProxyEventQueueTest::DidHandleInputEventAndOverscroll,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -563,7 +558,8 @@ class InputHandlerProxyEventQueueTest : public testing::TestWithParam<bool> {
return input_handler_proxy_->compositor_event_queue_->queue_;
}
- void SetInputHandlerProxyTickClockForTesting(base::TickClock* tick_clock) {
+ void SetInputHandlerProxyTickClockForTesting(
+ const base::TickClock* tick_clock) {
input_handler_proxy_->SetTickClockForTesting(tick_clock);
}
@@ -821,6 +817,59 @@ TEST_P(InputHandlerProxyTest, GestureScrollBeginThatTargetViewport) {
VERIFY_AND_RESET_MOCKS();
}
+void InputHandlerProxyTest::FlingAndSnap() {
+ expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+ VERIFY_AND_RESET_MOCKS();
+
+ EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+ .WillOnce(testing::Return(kImplThreadScrollState));
+
+ gesture_.SetType(WebInputEvent::kGestureScrollBegin);
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+ // The event should be dropped if InputHandler decides to snap.
+ expected_disposition_ = InputHandlerProxy::DROP_EVENT;
+ VERIFY_AND_RESET_MOCKS();
+
+ gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
+ gesture_.data.scroll_update.delta_y =
+ -40; // -Y means scroll down - i.e. in the +Y direction.
+ gesture_.data.scroll_update.inertial_phase =
+ blink::WebGestureEvent::kMomentumPhase;
+ EXPECT_CALL(mock_input_handler_,
+ GetSnapFlingInfo(testing::_, testing::_, testing::_))
+ .WillOnce(DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)),
+ testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)),
+ testing::Return(true)));
+ EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(1);
+ EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+ VERIFY_AND_RESET_MOCKS();
+}
+
+TEST_P(InputHandlerProxyTest, SnapFlingIgnoresFollowingGSUAndGSE) {
+ FlingAndSnap();
+ // The next GestureScrollUpdate should also be ignored, and will not ask for
+ // snap position.
+ expected_disposition_ = InputHandlerProxy::DROP_EVENT;
+
+ EXPECT_CALL(mock_input_handler_,
+ GetSnapFlingInfo(testing::_, testing::_, testing::_))
+ .Times(0);
+ EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+ VERIFY_AND_RESET_MOCKS();
+
+ // The GestureScrollEnd should also be ignored.
+ expected_disposition_ = InputHandlerProxy::DROP_EVENT;
+ gesture_.SetType(WebInputEvent::kGestureScrollEnd);
+ gesture_.data.scroll_end.inertial_phase =
+ blink::WebGestureEvent::kMomentumPhase;
+ EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, testing::_)).Times(0);
+ EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+ VERIFY_AND_RESET_MOCKS();
+}
+
TEST_P(InputHandlerProxyTest, GesturePinch) {
// We shouldn't send any events to the widget for this gesture.
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
@@ -837,8 +886,7 @@ TEST_P(InputHandlerProxyTest, GesturePinch) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 1.5;
- gesture_.x = 7;
- gesture_.y = 13;
+ gesture_.SetPositionInWidget(gfx::PointF(7, 13));
EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13)));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -847,8 +895,7 @@ TEST_P(InputHandlerProxyTest, GesturePinch) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 0.5;
gesture_.data.pinch_update.zoom_disabled = true;
- gesture_.x = 9;
- gesture_.y = 6;
+ gesture_.SetPositionInWidget(gfx::PointF(9, 6));
EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
input_handler_->HandleInputEvent(gesture_));
gesture_.data.pinch_update.zoom_disabled = false;
@@ -857,8 +904,7 @@ TEST_P(InputHandlerProxyTest, GesturePinch) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 0.5;
- gesture_.x = 9;
- gesture_.y = 6;
+ gesture_.SetPositionInWidget(gfx::PointF(9, 6));
EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6)));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -886,16 +932,14 @@ TEST_P(InputHandlerProxyTest, GesturePinchWithWheelHandler) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 1.5;
- gesture_.x = 7;
- gesture_.y = 13;
+ gesture_.SetPositionInWidget(gfx::PointF(7, 13));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
VERIFY_AND_RESET_MOCKS();
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 0.5;
- gesture_.x = 9;
- gesture_.y = 6;
+ gesture_.SetPositionInWidget(gfx::PointF(9, 6));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
VERIFY_AND_RESET_MOCKS();
@@ -938,8 +982,7 @@ TEST_P(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 1.5;
- gesture_.x = 7;
- gesture_.y = 13;
+ gesture_.SetPositionInWidget(gfx::PointF(7, 13));
EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13)));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -958,8 +1001,7 @@ TEST_P(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) {
gesture_.SetType(WebInputEvent::kGesturePinchUpdate);
gesture_.data.pinch_update.scale = 0.5;
- gesture_.x = 9;
- gesture_.y = 6;
+ gesture_.SetPositionInWidget(gfx::PointF(9, 6));
EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6)));
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1030,289 +1072,16 @@ void InputHandlerProxyTest::ScrollHandlingSwitchedToMainThread() {
VERIFY_AND_RESET_MOCKS();
}
TEST_P(InputHandlerProxyTest, WheelScrollHandlingSwitchedToMainThread) {
- gesture_.source_device = blink::kWebGestureDeviceTouchpad;
+ gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchpad);
ScrollHandlingSwitchedToMainThread();
}
TEST_P(InputHandlerProxyTest, TouchScrollHandlingSwitchedToMainThread) {
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
+ gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
ScrollHandlingSwitchedToMainThread();
}
-TEST_P(InputHandlerProxyTest, GestureFlingStartedTouchscreen) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- gesture_.data.fling_start.velocity_x = 10;
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
- // Verify that a GestureFlingCancel during an animation cancels it.
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingOnMainThreadTouchscreen) {
- // We should send all events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kMainThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin()).Times(0);
-
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Even if we didn't start a fling ourselves, we still need to send the cancel
- // event to the widget.
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) {
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- expected_disposition_ = InputHandlerProxy::DROP_EVENT;
- VERIFY_AND_RESET_MOCKS();
-
- // Flings ignored by the InputHandler should be dropped, signalling the end
- // of the touch scroll sequence.
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kScrollIgnoredScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Subsequent scrolls should behave normally, even without an intervening
- // GestureFlingCancel, as the original GestureFlingStart was dropped.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingAnimatesTouchscreen) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- // Note that for touchscreen the control modifier is not special.
- int modifiers = WebInputEvent::kControlKey;
- gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
- // The first animate call should let us pick up an animation start time, but
- // we shouldn't actually move anywhere just yet. The first frame after the
- // fling start will typically include the last scroll from the gesture that
- // lead to the scroll (either wheel or gesture scroll), so there should be no
- // visible hitch.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- // The second call should start scrolling in the -X direction.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithValidTimestamp) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey;
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
- // With a valid time stamp, the first animate call should skip start time
- // initialization and immediately begin scroll update production. This reduces
- // the likelihood of a hitch between the scroll preceding the fling and
- // the first scroll generated by the fling.
- // Scrolling should start in the -X direction.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += dt;
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- base::TimeDelta start_time_offset = base::TimeDelta::FromMilliseconds(10);
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey;
- gesture_.SetTimeStampSeconds(start_time_offset.InSecondsF());
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- gesture_.x = fling_point.x;
- gesture_.y = fling_point.y;
- gesture_.global_x = fling_global_point.x;
- gesture_.global_y = fling_global_point.y;
- gesture_.SetModifiers(modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
- // Event though a time stamp was provided for the fling event, it will be
- // ignored as its too far in the past relative to the first animate call's
- // timestamp.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- base::TimeTicks time =
- base::TimeTicks() + start_time_offset + base::TimeDelta::FromSeconds(1);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- // Further animation ticks should update the fling as usual.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureScrollOnImplThreadFlagClearedAfterFling) {
+TEST_P(InputHandlerProxyTest,
+ GestureScrollOnImplThreadFlagClearedAfterScrollEnd) {
// We shouldn't send any events to the widget for this gesture.
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
VERIFY_AND_RESET_MOCKS();
@@ -1327,56 +1096,15 @@ TEST_P(InputHandlerProxyTest, GestureScrollOnImplThreadFlagClearedAfterFling) {
// |gesture_scroll_on_impl_thread_| should be true.
EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
VERIFY_AND_RESET_MOCKS();
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey | WebInputEvent::kAltKey;
- gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- // |gesture_scroll_on_impl_thread_| should still be true after
- // a GestureFlingStart is sent.
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- VERIFY_AND_RESET_MOCKS();
- // The first animate call should let us pick up an animation start time, but
- // we shouldn't actually move anywhere just yet. The first frame after the
- // fling start will typically include the last scroll from the gesture that
- // lead to the scroll (either wheel or gesture scroll), so there should be no
- // visible hitch.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- // The second call should start scrolling in the -X direction.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
+ EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+ gesture_.SetType(WebInputEvent::kGestureScrollEnd);
EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- // |gesture_scroll_on_impl_thread_| should be false once
- // the fling has finished (note no GestureScrollEnd has been sent).
- EXPECT_TRUE(!input_handler_->gesture_scroll_on_impl_thread_for_testing());
+ // |gesture_scroll_on_impl_thread_| should be false once a GestureScrollEnd
+ // gets handled.
+ EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
VERIFY_AND_RESET_MOCKS();
}
@@ -1399,290 +1127,6 @@ TEST_P(InputHandlerProxyTest,
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey | WebInputEvent::kAltKey;
- gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- // |gesture_scroll_on_impl_thread_| should still be true after
- // a GestureFlingStart is sent.
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- VERIFY_AND_RESET_MOCKS();
-
- // gesture_scroll_on_impl_thread_ is still true when this scroll begins. As a
- // result, this scroll begin will cancel the previous fling.
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- // After sending a GestureScrollBegin, the member variable
- // |gesture_scroll_on_impl_thread_| should be true.
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingStopsAtContentEdgeTouchscreen) {
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- // HandleGestureScrollBegin will set gesture_scroll_on_impl_thread_.
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 100);
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- // The first animate doesn't cause any scrolling.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The second animate starts scrolling in the positive X and Y directions.
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The third animate overscrolls in the positive Y direction but scrolls
- // somewhat.
- cc::InputHandlerScrollResult overscroll;
- overscroll.did_scroll = true;
- overscroll.did_overscroll_root = true;
- overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
- overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
- .WillOnce(testing::Return(overscroll));
- EXPECT_CALL(
- mock_client_,
- DidOverscroll(overscroll.accumulated_root_overscroll,
- overscroll.unused_scroll_delta,
- testing::Property(&gfx::Vector2dF::y, testing::Lt(0)),
- testing::_, overscroll.overscroll_behavior));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The next call to animate will no longer scroll vertically.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingNotCancelledBySmallTimeDelta) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey;
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
- // With an animation timestamp equivalent to the starting timestamp, the
- // animation will simply be rescheduled.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- // A small time delta should not stop the fling, even if the client
- // reports no scrolling.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_not_scroll_));
- time += base::TimeDelta::FromMicroseconds(5);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- // A time delta of zero should not stop the fling, and neither should it
- // trigger scrolling on the client.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
- // Lack of movement on the client, with a non-trivial scroll delta, should
- // terminate the fling.
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(1))))
- .WillOnce(testing::Return(scroll_result_did_not_scroll_));
- time += base::TimeDelta::FromMilliseconds(100);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
- cc::InputHandlerScrollResult overscroll;
- overscroll.did_scroll = true;
- overscroll.did_overscroll_root = true;
-
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 100);
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- // The first animate doesn't cause any scrolling.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The second animate starts scrolling in the positive X and Y directions.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The third animate hits the bottom content edge.
- overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
- overscroll.unused_scroll_delta = gfx::Vector2dF(0, 100);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
- .WillOnce(testing::Return(overscroll));
- EXPECT_CALL(
- mock_client_,
- DidOverscroll(overscroll.accumulated_root_overscroll,
- overscroll.unused_scroll_delta,
- testing::Property(&gfx::Vector2dF::y, testing::Lt(0)),
- testing::_, overscroll.overscroll_behavior));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The next call to animate will no longer scroll vertically.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The next call will hit the right edge.
- overscroll.accumulated_root_overscroll = gfx::Vector2dF(100, 100);
- overscroll.unused_scroll_delta = gfx::Vector2dF(100, 0);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(overscroll));
- EXPECT_CALL(
- mock_client_,
- DidOverscroll(overscroll.accumulated_root_overscroll,
- overscroll.unused_scroll_delta,
- testing::Property(&gfx::Vector2dF::x, testing::Lt(0)),
- testing::_, overscroll.overscroll_behavior));
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // The next call to animate will no longer scroll horizontally or vertically,
- // and the fling should be cancelled.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(0);
- EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
- time += base::TimeDelta::FromMilliseconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
}
TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
@@ -1990,620 +1434,6 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
VERIFY_AND_RESET_MOCKS();
}
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) {
- // We shouldn't send any events to the widget for this gesture.
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
- input_handler_->HandleInputEvent(gesture_));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // Keyboard events received during a scroll should have no effect.
- WebKeyboardEvent key_event(WebInputEvent::kKeyDown,
- WebInputEvent::kNoModifiers,
- WebInputEvent::GetStaticTimeStampForTests());
- EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
- input_handler_->HandleInputEvent(key_event));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, animation should be scheduled, but no scrolling occurs.
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 100);
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // Keyboard events received during a fling should cancel the active fling.
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
- input_handler_->HandleInputEvent(key_event));
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // The call to animate should have no effect, as the fling was cancelled.
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // A fling cancel should be dropped, as there is nothing to cancel.
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
- input_handler_->HandleInputEvent(gesture_));
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledByWheelEvent) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // Wheel events received during a scroll shouldn't cancel the fling, but will
- // cause scrolling.
- cc::InputHandlerScrollResult result;
-
- EXPECT_CALL(mock_input_handler_,
- GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
- .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
-
- WebMouseWheelEvent wheel_event(WebInputEvent::kMouseWheel,
- WebInputEvent::kNoModifiers,
- WebInputEvent::GetStaticTimeStampForTests());
- input_handler_->HandleInputEvent(wheel_event);
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, animation should be scheduled, but no scrolling occurs.
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 100);
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // Wheel events received during a fling should cancel the active fling, and
- // cause a scroll.
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
- EXPECT_CALL(mock_input_handler_,
- GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
- .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
-
- input_handler_->HandleInputEvent(wheel_event);
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
- VERIFY_AND_RESET_MOCKS();
-
- // The call to animate should have no effect, as the fling was cancelled.
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
- VERIFY_AND_RESET_MOCKS();
-
- // A fling cancel should be dropped, as there is nothing to cancel.
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
- input_handler_->HandleInputEvent(gesture_));
- EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithNegativeTimeDelta) {
- // We shouldn't send any events to the widget for this gesture.
- expected_disposition_ = InputHandlerProxy::DID_HANDLE;
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // On the fling start, we should schedule an animation but not actually start
- // scrolling.
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(100, 0);
- WebPoint fling_point = WebPoint(7, 13);
- WebPoint fling_global_point = WebPoint(17, 23);
- int modifiers = WebInputEvent::kControlKey;
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_global_point, modifiers);
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // If we get a negative time delta, that is, the Animation tick time happens
- // before the fling's start time then we should *not* try scrolling and
- // instead reset the fling start time.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
- time -= base::TimeDelta::FromMilliseconds(5);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- // The first call should have reset the start time so subsequent calls should
- // generate scroll events.
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
-
- Animate(time + base::TimeDelta::FromMilliseconds(1));
-
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, FlingBoost) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- base::TimeTicks last_animate_time = time;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Now cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // The GestureScrollBegin should be swallowed by the fling if a fling cancel
- // is deferred.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Animate calls within the deferred cancellation window should continue.
- time += dt;
- float expected_delta =
- (time - last_animate_time).InSecondsF() * -fling_delta.x;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
- last_animate_time = time;
-
- VERIFY_AND_RESET_MOCKS();
-
- // GestureScrollUpdates in the same direction and at sufficient speed should
- // be swallowed by the fling.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
- gesture_.data.scroll_update.delta_x = fling_delta.x;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Animate calls within the deferred cancellation window should continue.
- time += dt;
- expected_delta = (time - last_animate_time).InSecondsF() * -fling_delta.x;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
- last_animate_time = time;
-
- VERIFY_AND_RESET_MOCKS();
-
- // GestureFlingStart in the same direction and at sufficient speed should
- // boost the active fling.
-
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_point, 0);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- time += dt;
- // Note we get *2x* as much delta because 2 flings have combined.
- expected_delta = 2 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
- last_animate_time = time;
-
- VERIFY_AND_RESET_MOCKS();
-
- // Repeated GestureFlingStarts should accumulate.
-
- CancelFling(time);
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point, fling_point, 0);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- time += dt;
- // Note we get *3x* as much delta because 3 flings have combined.
- expected_delta = 3 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
- last_animate_time = time;
-
- VERIFY_AND_RESET_MOCKS();
-
- // GestureFlingCancel should terminate the fling if no boosting gestures are
- // received within the timeout window.
-
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- time += base::TimeDelta::FromMilliseconds(100);
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollDelayed) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // The GestureScrollBegin should be swallowed by the fling if a fling cancel
- // is deferred.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // If no GestureScrollUpdate or GestureFlingStart is received within the
- // timeout window, the fling should be cancelled and scrolling should resume.
- time += base::TimeDelta::FromMilliseconds(100);
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfNotAnimated) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Animate fling once.
- time += dt;
- EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- Animate(time);
-
- // Cancel the fling after long delay of no animate. The fling cancellation
- // should be deferred to allow fling boosting events to arrive.
- time += base::TimeDelta::FromMilliseconds(100);
- CancelFling(time);
-
- // The GestureScrollBegin should be swallowed by the fling if a fling cancel
- // is deferred.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Should exit scroll bosting on GestureScrollUpdate due to long delay
- // since last animate. Cancel old fling and start new scroll.
- gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
- gesture_.data.scroll_update.delta_y = -40;
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingInDifferentDirection) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // If the new fling is orthogonal to the existing fling, no boosting should
- // take place, with the new fling replacing the old.
- WebFloatPoint orthogonal_fling_delta =
- WebFloatPoint(fling_delta.y, -fling_delta.x);
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen,
- orthogonal_fling_delta, fling_point, fling_point, 0);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Note that the new fling delta uses the orthogonal, unboosted fling
- // velocity.
- time += dt;
- float expected_delta = dt.InSecondsF() * -orthogonal_fling_delta.y;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollInDifferentDirection) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // The GestureScrollBegin should be swallowed by the fling if a fling cancel
- // is deferred.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // If the GestureScrollUpdate is in a different direction than the fling,
- // the fling should be cancelled and scrolling should resume.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
- gesture_.data.scroll_update.delta_x = -fling_delta.x;
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(fling_delta.x))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingTooSlow) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // If the new fling is too slow, no boosting should take place, with the new
- // fling replacing the old.
- WebFloatPoint small_fling_delta = WebFloatPoint(100, 0);
- gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen,
- small_fling_delta, fling_point, fling_point, 0);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Note that the new fling delta uses the *slow*, unboosted fling velocity.
- time += dt;
- float expected_delta = dt.InSecondsF() * -small_fling_delta.x;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfPreventBoostingFlagIsSet) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
-
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
- // Cancel the fling. The fling cancellation should not be deferred because of
- // prevent boosting flag set.
- gesture_.data.fling_cancel.prevent_boosting = true;
- time += dt;
- CancelFling(time);
-
- // VERIFY_AND_RESET_MOCKS already called by CancelFling
-}
-
-TEST_P(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) {
- base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks time = base::TimeTicks() + dt;
- base::TimeTicks last_animate_time = time;
- WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
- WebPoint fling_point = WebPoint(7, 13);
- StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
- fling_point);
-
- // Now cancel the fling. The fling cancellation should be deferred to allow
- // fling boosting events to arrive.
- time += dt;
- CancelFling(time);
-
- // The GestureScrollBegin should be swallowed by the fling.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // Now animate the fling to completion (in this case, the fling should
- // terminate because the input handler reports a failed scroll). As the fling
- // was cancelled during an active scroll sequence, a synthetic
- // GestureScrollBegin should be processed, resuming the scroll.
- time += dt;
- float expected_delta =
- (time - last_animate_time).InSecondsF() * -fling_delta.x;
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_not_scroll_));
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-
- // Subsequent GestureScrollUpdates after the cancelled, boosted fling should
- // cause scrolling as usual.
- time += dt;
- expected_delta = 7.3f;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
- gesture_.data.scroll_update.delta_x = -expected_delta;
- EXPECT_CALL(mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_x,
- testing::Eq(expected_delta))))
- .WillOnce(testing::Return(scroll_result_did_scroll_));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- // GestureScrollEnd should terminate the resumed scroll properly.
- time += dt;
- gesture_.SetTimeStampSeconds(InSecondsF(time));
- gesture_.SetType(WebInputEvent::kGestureScrollEnd);
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, DidReceiveInputEvent_ForFlingTouchscreen) {
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- testing::StrictMock<MockInputHandlerProxyClientWithDidAnimateForInput>
- mock_client;
- input_handler_.reset(
- new TestInputHandlerProxy(&mock_input_handler_, &mock_client,
- touchpad_and_wheel_scroll_latching_enabled_,
- async_wheel_events_enabled_));
- if (install_synchronous_handler_) {
- EXPECT_CALL(mock_input_handler_, RequestUpdateForSynchronousInputHandler())
- .Times(1);
- input_handler_->SetOnlySynchronouslyAnimateRootFlings(
- &mock_synchronous_input_handler_);
- }
- mock_input_handler_.set_is_scrolling_root(synchronous_root_scroll_);
-
- // A GSB must be sent before a GFS.
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillOnce(testing::Return(kImplThreadScrollState));
- gesture_.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_.source_device = blink::kWebGestureDeviceTouchscreen;
- EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
- VERIFY_AND_RESET_MOCKS();
-
- gesture_.SetType(WebInputEvent::kGestureFlingStart);
- WebFloatPoint fling_delta = WebFloatPoint(100, 100);
- gesture_.data.fling_start.velocity_x = fling_delta.x;
- gesture_.data.fling_start.velocity_y = fling_delta.y;
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
- EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
- input_handler_->HandleInputEvent(gesture_));
- VERIFY_AND_RESET_MOCKS();
-
- EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
- EXPECT_CALL(mock_client, DidAnimateForInput());
- base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
- Animate(time);
-
- VERIFY_AND_RESET_MOCKS();
-}
-
TEST(SynchronousInputHandlerProxyTest, StartupShutdown) {
testing::StrictMock<MockInputHandler> mock_input_handler;
testing::StrictMock<MockInputHandlerProxyClient> mock_client;
@@ -2712,13 +1542,15 @@ TEST_P(InputHandlerProxyTest, GestureScrollingThreadStatusHistogram) {
touch_start.touches[0] =
CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
- WebGestureEvent gesture_scroll_begin;
- gesture_scroll_begin.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen;
+ WebGestureEvent gesture_scroll_begin(
+ WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ blink::kWebGestureDeviceTouchscreen);
- WebGestureEvent gesture_scroll_end;
- gesture_scroll_end.SetType(WebInputEvent::kGestureScrollEnd);
- gesture_scroll_end.source_device = blink::kWebGestureDeviceTouchscreen;
+ WebGestureEvent gesture_scroll_end(
+ WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ blink::kWebGestureDeviceTouchscreen);
// Touch start with passive event listener.
EXPECT_CALL(
@@ -2816,13 +1648,15 @@ TEST_P(InputHandlerProxyTest, WheelScrollingThreadStatusHistogram) {
WebInputEvent::kControlKey,
WebInputEvent::GetStaticTimeStampForTests());
- WebGestureEvent gesture_scroll_begin;
- gesture_scroll_begin.SetType(WebInputEvent::kGestureScrollBegin);
- gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchpad;
+ WebGestureEvent gesture_scroll_begin(
+ WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ blink::kWebGestureDeviceTouchpad);
- WebGestureEvent gesture_scroll_end;
- gesture_scroll_end.SetType(WebInputEvent::kGestureScrollEnd);
- gesture_scroll_end.source_device = blink::kWebGestureDeviceTouchpad;
+ WebGestureEvent gesture_scroll_end(
+ WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ blink::kWebGestureDeviceTouchpad);
// Wheel event with passive event listener.
EXPECT_CALL(mock_input_handler_,
@@ -3073,12 +1907,15 @@ TEST_P(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
// GSUs and GPUs in one sequence should be coalesced into 1 GSU and 1 GPU.
HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
+ HandleGestureEvent(WebInputEvent::kGesturePinchBegin);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -7);
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 2.0f, 13, 10);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -10);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -6);
+ HandleGestureEvent(WebInputEvent::kGesturePinchEnd);
HandleGestureEvent(WebInputEvent::kGestureScrollEnd);
+ HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
HandleGestureEvent(WebInputEvent::kGesturePinchBegin);
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 0.2f, 2, 20);
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 10.0f, 1, 10);
@@ -3086,37 +1923,46 @@ TEST_P(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 0.25f, 3, 30);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -10);
HandleGestureEvent(WebInputEvent::kGesturePinchEnd);
+ HandleGestureEvent(WebInputEvent::kGestureScrollEnd);
// Only the first GSB was dispatched.
- EXPECT_EQ(7ul, event_queue().size());
+ EXPECT_EQ(11ul, event_queue().size());
EXPECT_EQ(1ul, event_disposition_recorder_.size());
- EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
+ EXPECT_EQ(WebInputEvent::kGesturePinchBegin,
event_queue()[0]->event().GetType());
+ EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
+ event_queue()[1]->event().GetType());
EXPECT_EQ(
-35,
- ToWebGestureEvent(event_queue()[0]->event()).data.scroll_update.delta_y);
+ ToWebGestureEvent(event_queue()[1]->event()).data.scroll_update.delta_y);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
- event_queue()[1]->event().GetType());
+ event_queue()[2]->event().GetType());
EXPECT_EQ(
2.0f,
- ToWebGestureEvent(event_queue()[1]->event()).data.pinch_update.scale);
+ ToWebGestureEvent(event_queue()[2]->event()).data.pinch_update.scale);
+ EXPECT_EQ(WebInputEvent::kGesturePinchEnd,
+ event_queue()[3]->event().GetType());
EXPECT_EQ(WebInputEvent::kGestureScrollEnd,
- event_queue()[2]->event().GetType());
+ event_queue()[4]->event().GetType());
+ EXPECT_EQ(WebInputEvent::kGestureScrollBegin,
+ event_queue()[5]->event().GetType());
EXPECT_EQ(WebInputEvent::kGesturePinchBegin,
- event_queue()[3]->event().GetType());
+ event_queue()[6]->event().GetType());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
- event_queue()[4]->event().GetType());
+ event_queue()[7]->event().GetType());
EXPECT_EQ(
-85,
- ToWebGestureEvent(event_queue()[4]->event()).data.scroll_update.delta_y);
+ ToWebGestureEvent(event_queue()[7]->event()).data.scroll_update.delta_y);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
- event_queue()[5]->event().GetType());
+ event_queue()[8]->event().GetType());
EXPECT_EQ(
0.5f,
- ToWebGestureEvent(event_queue()[5]->event()).data.pinch_update.scale);
+ ToWebGestureEvent(event_queue()[8]->event()).data.pinch_update.scale);
EXPECT_EQ(WebInputEvent::kGesturePinchEnd,
- event_queue()[6]->event().GetType());
+ event_queue()[9]->event().GetType());
+ EXPECT_EQ(WebInputEvent::kGestureScrollEnd,
+ event_queue()[10]->event().GetType());
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
}
@@ -3136,6 +1982,10 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true))
.Times(::testing::AtLeast(1));
+ EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
+ EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(testing::_, testing::_));
+ EXPECT_CALL(mock_input_handler_, PinchGestureEnd(testing::_, testing::_));
+
trace_analyzer::Start("*");
// Simulate scroll.
HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
@@ -3146,10 +1996,12 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
// Simulate scroll and pinch.
HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
+ HandleGestureEvent(WebInputEvent::kGesturePinchBegin);
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 10.0f, 1, 10);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -10);
HandleGestureEvent(WebInputEvent::kGesturePinchUpdate, 2.0f, 1, 10);
HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -30);
+ HandleGestureEvent(WebInputEvent::kGesturePinchEnd);
HandleGestureEvent(WebInputEvent::kGestureScrollEnd);
// Dispatch all events.
@@ -3167,8 +2019,8 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END);
analyzer->FindEvents(end_query, &end_events);
- EXPECT_EQ(5ul, begin_events.size());
- EXPECT_EQ(5ul, end_events.size());
+ EXPECT_EQ(7ul, begin_events.size());
+ EXPECT_EQ(7ul, end_events.size());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
end_events[0]->GetKnownArgAsInt("type"));
EXPECT_EQ(3, end_events[0]->GetKnownArgAsInt("coalesced_count"));
@@ -3177,107 +2029,22 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
EXPECT_EQ(WebInputEvent::kGestureScrollBegin,
end_events[2]->GetKnownArgAsInt("type"));
+ EXPECT_EQ(WebInputEvent::kGesturePinchBegin,
+ end_events[3]->GetKnownArgAsInt("type"));
// Original scroll and pinch updates will be stored in the coalesced
// PinchUpdate of the <ScrollUpdate, PinchUpdate> pair.
// The ScrollUpdate of the pair doesn't carry original events and won't be
// traced.
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
- end_events[3]->GetKnownArgAsInt("type"));
- EXPECT_EQ(4, end_events[3]->GetKnownArgAsInt("coalesced_count"));
- EXPECT_EQ(WebInputEvent::kGestureScrollEnd,
end_events[4]->GetKnownArgAsInt("type"));
+ EXPECT_EQ(4, end_events[4]->GetKnownArgAsInt("coalesced_count"));
+ EXPECT_EQ(WebInputEvent::kGesturePinchEnd,
+ end_events[5]->GetKnownArgAsInt("type"));
+ EXPECT_EQ(WebInputEvent::kGestureScrollEnd,
+ end_events[6]->GetKnownArgAsInt("type"));
testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
}
-TEST_P(InputHandlerProxyEventQueueTest, GestureScrollFlingOrder) {
- // Handle scroll on compositor.
- cc::InputHandlerScrollResult scroll_result_did_scroll_;
- scroll_result_did_scroll_.did_scroll = true;
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillRepeatedly(testing::Return(kImplThreadScrollState));
- EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
- .Times(::testing::AtLeast(1));
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
- .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false))
- .Times(::testing::AtLeast(1));
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- // Simulate scroll.
- HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
- HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
- HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -30);
- HandleGestureEvent(WebInputEvent::kGestureFlingStart, -10);
-
- // ScrollUpdate and FlingStart should be queued.
- EXPECT_EQ(2ul, event_queue().size());
- EXPECT_EQ(1ul, event_disposition_recorder_.size());
- EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
- event_queue()[0]->event().GetType());
- EXPECT_EQ(WebInputEvent::kGestureFlingStart,
- event_queue()[1]->event().GetType());
-
- // Dispatch events.
- input_handler_proxy_->DeliverInputForBeginFrame();
- EXPECT_EQ(0ul, event_queue().size());
- EXPECT_EQ(4ul, event_disposition_recorder_.size());
- EXPECT_TRUE(
- input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-
- // Send FlingCancel to stop scrolling.
- HandleGestureEvent(WebInputEvent::kGestureFlingCancel);
- EXPECT_EQ(1ul, event_queue().size());
- EXPECT_EQ(WebInputEvent::kGestureFlingCancel,
- event_queue()[0]->event().GetType());
- input_handler_proxy_->DeliverInputForBeginFrame();
- EXPECT_EQ(0ul, event_queue().size());
- EXPECT_EQ(5ul, event_disposition_recorder_.size());
- // Should stop scrolling. Note that no ScrollEnd was sent.
- EXPECT_TRUE(
- !input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyEventQueueTest, GestureScrollAfterFling) {
- // Handle scroll on compositor.
- cc::InputHandlerScrollResult scroll_result_did_scroll_;
- scroll_result_did_scroll_.did_scroll = true;
-
- EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
- .WillRepeatedly(testing::Return(kImplThreadScrollState));
- EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
- .Times(::testing::AtLeast(1));
- EXPECT_CALL(
- mock_input_handler_,
- ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
- .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
- EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false))
- .Times(::testing::AtLeast(1));
- EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
- .WillOnce(testing::Return(kImplThreadScrollState));
-
- // Simulate fling.
- HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
- HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
- HandleGestureEvent(WebInputEvent::kGestureFlingStart, -10);
- HandleGestureEvent(WebInputEvent::kGestureFlingCancel);
-
- // Dispatch events.
- input_handler_proxy_->DeliverInputForBeginFrame();
- EXPECT_EQ(0ul, event_queue().size());
- EXPECT_EQ(4ul, event_disposition_recorder_.size());
- EXPECT_FALSE(
- input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-
- // New ScrollBegin should be dispatched immediately as there is no on-going
- // scroll, fling or pinch.
- HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
- EXPECT_EQ(0ul, event_queue().size());
-}
-
TEST_P(InputHandlerProxyEventQueueTest, TouchpadGestureScrollEndFlushQueue) {
// Handle scroll on compositor.
cc::InputHandlerScrollResult scroll_result_did_scroll_;
diff --git a/chromium/ui/events/blink/input_scroll_elasticity_controller.h b/chromium/ui/events/blink/input_scroll_elasticity_controller.h
index 6c083053b29..f5478b5ca5b 100644
--- a/chromium/ui/events/blink/input_scroll_elasticity_controller.h
+++ b/chromium/ui/events/blink/input_scroll_elasticity_controller.h
@@ -9,8 +9,8 @@
#include "base/memory/weak_ptr.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/input/scroll_elasticity_helper.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_input_event.h"
// InputScrollElasticityController is based on
// WebKit/Source/platform/mac/ScrollElasticityController.h
diff --git a/chromium/ui/events/blink/input_scroll_elasticity_controller_unittest.cc b/chromium/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
index 777b5c933b4..e162423b553 100644
--- a/chromium/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
+++ b/chromium/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
@@ -6,8 +6,8 @@
#include "cc/input/input_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
namespace ui {
namespace {
@@ -93,8 +93,8 @@ class ScrollElasticityControllerTest : public testing::Test {
blink::WebGestureEvent event(
blink::WebInputEvent::kGestureScrollBegin,
blink::WebInputEvent::kNoModifiers,
- (current_time_ - base::TimeTicks()).InSecondsF());
- event.source_device = blink::kWebGestureDeviceTouchpad;
+ (current_time_ - base::TimeTicks()).InSecondsF(),
+ blink::kWebGestureDeviceTouchpad);
event.data.scroll_begin.inertial_phase =
static_cast<blink::WebGestureEvent::InertialPhaseState>(inertialPhase);
@@ -113,8 +113,8 @@ class ScrollElasticityControllerTest : public testing::Test {
blink::WebGestureEvent event(
blink::WebInputEvent::kGestureScrollUpdate,
blink::WebInputEvent::kNoModifiers,
- (current_time_ - base::TimeTicks()).InSecondsF());
- event.source_device = blink::kWebGestureDeviceTouchpad;
+ (current_time_ - base::TimeTicks()).InSecondsF(),
+ blink::kWebGestureDeviceTouchpad);
event.data.scroll_update.inertial_phase =
static_cast<blink::WebGestureEvent::InertialPhaseState>(inertialPhase);
event.data.scroll_update.delta_x = -event_delta.x();
@@ -134,8 +134,8 @@ class ScrollElasticityControllerTest : public testing::Test {
blink::WebGestureEvent event(
blink::WebInputEvent::kGestureScrollEnd,
blink::WebInputEvent::kNoModifiers,
- (current_time_ - base::TimeTicks()).InSecondsF());
- event.source_device = blink::kWebGestureDeviceTouchpad;
+ (current_time_ - base::TimeTicks()).InSecondsF(),
+ blink::kWebGestureDeviceTouchpad);
controller_.ObserveGestureEventAndResult(event,
cc::InputHandlerScrollResult());
diff --git a/chromium/ui/events/blink/snap_fling_controller.cc b/chromium/ui/events/blink/snap_fling_controller.cc
new file mode 100644
index 00000000000..35ae2b96145
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_controller.cc
@@ -0,0 +1,102 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/blink/snap_fling_controller.h"
+
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "ui/events/blink/snap_fling_curve.h"
+
+namespace ui {
+
+SnapFlingController::SnapFlingController(SnapFlingClient* client)
+ : client_(client), state_(State::kIdle) {}
+
+SnapFlingController::~SnapFlingController() = default;
+
+bool SnapFlingController::FilterEventForSnap(
+ const blink::WebInputEvent& event) {
+ switch (event.GetType()) {
+ case blink::WebInputEvent::kGestureScrollBegin: {
+ ClearSnapFling();
+ return false;
+ }
+ // TODO(sunyunjia): Need to update the existing snap curve if the GSU is
+ // from a fling boosting event.
+ case blink::WebInputEvent::kGestureScrollUpdate:
+ case blink::WebInputEvent::kGestureScrollEnd: {
+ return state_ == State::kActive || state_ == State::kFinished;
+ }
+ default:
+ return false;
+ }
+}
+
+void SnapFlingController::ClearSnapFling() {
+ if (state_ == State::kActive)
+ client_->ScrollEndForSnapFling();
+
+ curve_.reset();
+ state_ = State::kIdle;
+}
+
+bool SnapFlingController::HandleGestureScrollUpdate(
+ const blink::WebGestureEvent& event) {
+ DCHECK(state_ != State::kActive && state_ != State::kFinished);
+ if (state_ != State::kIdle)
+ return false;
+
+ if (event.data.scroll_update.inertial_phase !=
+ blink::WebGestureEvent::kMomentumPhase) {
+ return false;
+ }
+
+ gfx::Vector2dF event_delta(-event.data.scroll_update.delta_x,
+ -event.data.scroll_update.delta_y);
+ gfx::Vector2dF ending_displacement =
+ SnapFlingCurve::EstimateDisplacement(event_delta);
+
+ gfx::Vector2dF target_offset, start_offset;
+ if (!client_->GetSnapFlingInfo(ending_displacement, &start_offset,
+ &target_offset)) {
+ state_ = State::kIgnored;
+ return false;
+ }
+
+ if (start_offset == target_offset) {
+ state_ = State::kFinished;
+ return true;
+ }
+
+ base::TimeTicks event_time =
+ base::TimeTicks() +
+ base::TimeDelta::FromSecondsD(event.TimeStampSeconds());
+ curve_ =
+ std::make_unique<SnapFlingCurve>(start_offset, target_offset, event_time);
+ state_ = State::kActive;
+ Animate(event_time);
+ return true;
+}
+
+void SnapFlingController::Animate(base::TimeTicks time) {
+ if (state_ != State::kActive)
+ return;
+
+ if (curve_->IsFinished()) {
+ client_->ScrollEndForSnapFling();
+ state_ = State::kFinished;
+ return;
+ }
+ gfx::Vector2dF snapped_delta = curve_->GetScrollDelta(time);
+ gfx::Vector2dF current_offset = client_->ScrollByForSnapFling(snapped_delta);
+ curve_->UpdateCurrentOffset(current_offset);
+ client_->RequestAnimationForSnapFling();
+}
+
+void SnapFlingController::SetCurveForTest(
+ std::unique_ptr<SnapFlingCurve> curve) {
+ curve_ = std::move(curve);
+ state_ = State::kActive;
+}
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/events/blink/snap_fling_controller.h b/chromium/ui/events/blink/snap_fling_controller.h
new file mode 100644
index 00000000000..52413b75377
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_controller.h
@@ -0,0 +1,96 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_BLINK_SNAP_FLING_CONTROLLER_H_
+#define UI_EVENTS_BLINK_SNAP_FLING_CONTROLLER_H_
+
+#include <memory>
+
+#include "base/time/time.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace blink {
+class WebGestureEvent;
+class WebInputEvent;
+} // namespace blink
+
+namespace ui {
+namespace test {
+class SnapFlingControllerTest;
+}
+
+class SnapFlingCurve;
+
+// A client that provides information to the controller. It also executes the
+// scroll operations and requests animation frames. All the inputs and outputs
+// are in the same coordinate space.
+class SnapFlingClient {
+ public:
+ virtual bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset) const = 0;
+ virtual gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) = 0;
+ virtual void ScrollEndForSnapFling() = 0;
+ virtual void RequestAnimationForSnapFling() = 0;
+};
+
+class SnapFlingController {
+ public:
+ explicit SnapFlingController(SnapFlingClient* client);
+
+ static std::unique_ptr<SnapFlingController> CreateForTests(
+ SnapFlingClient* client,
+ std::unique_ptr<SnapFlingCurve> curve);
+
+ ~SnapFlingController();
+
+ // Returns true if the event should be consumed for snapping and should not be
+ // processed further.
+ bool FilterEventForSnap(const blink::WebInputEvent& event);
+
+ // Creates the snap fling curve from the first inertial GSU. Returns true if
+ // the event if a snap fling curve has been created and the event should not
+ // be processed further.
+ bool HandleGestureScrollUpdate(const blink::WebGestureEvent& event);
+
+ // Notifies the snap fling controller to update or end the scroll animation.
+ void Animate(base::TimeTicks time);
+
+ private:
+ friend class test::SnapFlingControllerTest;
+
+ enum class State {
+ // We haven't received an inertial GSU in this scroll sequence.
+ kIdle,
+ // We have received an inertial GSU but decided not to snap for this scroll
+ // sequence.
+ kIgnored,
+ // We have received an inertial GSU and decided to snap and animate it for
+ // this scroll sequence. So subsequent GSUs and GSE in the scroll sequence
+ // are consumed for snapping.
+ kActive,
+ // The animation of the snap fling has finished for this scroll sequence.
+ // Subsequent GSUs and GSE in the scroll sequence are ignored.
+ kFinished,
+ };
+
+ SnapFlingController(SnapFlingClient* client,
+ std::unique_ptr<SnapFlingCurve> curve);
+ void ClearSnapFling();
+
+ // Sets the |curve_| to |curve| and the |state| to |kActive|.
+ void SetCurveForTest(std::unique_ptr<SnapFlingCurve> curve);
+
+ void SetActiveStateForTest() { state_ = State::kActive; }
+
+ SnapFlingClient* client_;
+ State state_ = State::kIdle;
+ std::unique_ptr<SnapFlingCurve> curve_;
+
+ DISALLOW_COPY_AND_ASSIGN(SnapFlingController);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_BLINK_SNAP_FLING_CONTROLLER_H_ \ No newline at end of file
diff --git a/chromium/ui/events/blink/snap_fling_controller_unittest.cc b/chromium/ui/events/blink/snap_fling_controller_unittest.cc
new file mode 100644
index 00000000000..e627b093e03
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_controller_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/blink/snap_fling_controller.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "ui/events/blink/snap_fling_curve.h"
+
+namespace ui {
+namespace test {
+namespace {
+
+class MockSnapFlingClient : public SnapFlingClient {
+ public:
+ MOCK_CONST_METHOD3(GetSnapFlingInfo,
+ bool(const gfx::Vector2dF& natural_displacement,
+ gfx::Vector2dF* initial_offset,
+ gfx::Vector2dF* target_offset));
+ MOCK_METHOD0(ScrollEndForSnapFling, void());
+ MOCK_METHOD0(RequestAnimationForSnapFling, void());
+ MOCK_METHOD1(ScrollByForSnapFling, gfx::Vector2dF(const gfx::Vector2dF&));
+};
+
+class MockSnapFlingCurve : public SnapFlingCurve {
+ public:
+ MockSnapFlingCurve()
+ : SnapFlingCurve(gfx::Vector2dF(),
+ gfx::Vector2dF(0, 100),
+ base::TimeTicks()) {}
+ MOCK_CONST_METHOD0(IsFinished, bool());
+ MOCK_METHOD1(GetScrollDelta, gfx::Vector2dF(base::TimeTicks));
+};
+
+} // namespace
+
+class SnapFlingControllerTest : public testing::Test {
+ public:
+ SnapFlingControllerTest() {
+ controller_ = std::make_unique<SnapFlingController>(&mock_client_);
+ }
+ void SetCurve(std::unique_ptr<SnapFlingCurve> curve) {
+ controller_->SetCurveForTest(std::move(curve));
+ }
+ void SetActiveState() { controller_->SetActiveStateForTest(); }
+
+ protected:
+ testing::StrictMock<MockSnapFlingClient> mock_client_;
+ std::unique_ptr<SnapFlingController> controller_;
+};
+
+TEST_F(SnapFlingControllerTest, DoesNotFilterGSBWhenIdle) {
+ blink::WebGestureEvent event(blink::WebInputEvent::kGestureScrollBegin, 0, 0);
+ EXPECT_FALSE(controller_->FilterEventForSnap(event));
+}
+
+TEST_F(SnapFlingControllerTest, FiltersGSUAndGSEDependingOnState) {
+ blink::WebGestureEvent scroll_update(
+ blink::WebInputEvent::kGestureScrollUpdate, 0, 0);
+ blink::WebGestureEvent scroll_end(blink::WebInputEvent::kGestureScrollEnd, 0,
+ 0);
+ // Should not filter GSU and GSE if the fling is not active.
+ EXPECT_FALSE(controller_->FilterEventForSnap(scroll_update));
+ EXPECT_FALSE(controller_->FilterEventForSnap(scroll_end));
+
+ // Should filter GSU and GSE if the fling is active.
+ SetActiveState();
+ EXPECT_TRUE(controller_->FilterEventForSnap(scroll_update));
+ EXPECT_TRUE(controller_->FilterEventForSnap(scroll_end));
+}
+
+TEST_F(SnapFlingControllerTest, CreatesAndAnimatesCurveOnFirstInertialGSU) {
+ blink::WebGestureEvent event(blink::WebInputEvent::kGestureScrollUpdate, 0,
+ 0);
+ event.data.scroll_update.delta_x = 0;
+ event.data.scroll_update.delta_y = -10;
+ event.data.scroll_update.inertial_phase =
+ blink::WebGestureEvent::kMomentumPhase;
+
+ EXPECT_CALL(mock_client_,
+ GetSnapFlingInfo(testing::_, testing::_, testing::_))
+ .WillOnce(DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)),
+ testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)),
+ testing::Return(true)));
+ EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(1);
+ EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(1);
+ EXPECT_TRUE(controller_->HandleGestureScrollUpdate(event));
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+}
+
+TEST_F(SnapFlingControllerTest, DoesNotHandleNonInertialGSU) {
+ blink::WebGestureEvent event(blink::WebInputEvent::kGestureScrollUpdate, 0,
+ 0);
+ event.data.scroll_update.delta_x = 0;
+ event.data.scroll_update.delta_y = -10;
+ event.data.scroll_update.inertial_phase =
+ blink::WebGestureEvent::kNonMomentumPhase;
+
+ EXPECT_CALL(mock_client_,
+ GetSnapFlingInfo(testing::_, testing::_, testing::_))
+ .Times(0);
+ EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(0);
+ EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(0);
+ EXPECT_FALSE(controller_->HandleGestureScrollUpdate(event));
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+}
+
+TEST_F(SnapFlingControllerTest, AnimatesTheCurve) {
+ std::unique_ptr<MockSnapFlingCurve> mock_curve =
+ std::make_unique<MockSnapFlingCurve>();
+ MockSnapFlingCurve* curve = mock_curve.get();
+ SetCurve(std::move(mock_curve));
+
+ EXPECT_CALL(*curve, IsFinished()).WillOnce(testing::Return(false));
+ EXPECT_CALL(*curve, GetScrollDelta(testing::_))
+ .WillOnce(testing::Return(gfx::Vector2dF(100, 100)));
+ EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(1);
+ EXPECT_CALL(mock_client_, ScrollByForSnapFling(gfx::Vector2dF(100, 100)));
+ controller_->Animate(base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+ testing::Mock::VerifyAndClearExpectations(curve);
+}
+
+TEST_F(SnapFlingControllerTest, FinishesTheCurve) {
+ std::unique_ptr<MockSnapFlingCurve> mock_curve =
+ std::make_unique<MockSnapFlingCurve>();
+ MockSnapFlingCurve* curve = mock_curve.get();
+ SetCurve(std::move(mock_curve));
+ EXPECT_CALL(*curve, IsFinished()).WillOnce(testing::Return(true));
+ EXPECT_CALL(*curve, GetScrollDelta(testing::_)).Times(0);
+ EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(0);
+ EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(0);
+ EXPECT_CALL(mock_client_, ScrollEndForSnapFling()).Times(1);
+ controller_->Animate(base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ testing::Mock::VerifyAndClearExpectations(curve);
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+
+ EXPECT_CALL(*curve, IsFinished()).Times(0);
+ EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(0);
+ EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(0);
+ EXPECT_CALL(mock_client_, ScrollEndForSnapFling()).Times(0);
+ controller_->Animate(base::TimeTicks() + base::TimeDelta::FromSeconds(2));
+ testing::Mock::VerifyAndClearExpectations(curve);
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+}
+
+TEST_F(SnapFlingControllerTest, GSBNotFilteredAndResetsStateWhenActive) {
+ SetActiveState();
+ blink::WebGestureEvent update_event(
+ blink::WebInputEvent::kGestureScrollUpdate, 0, 0);
+ update_event.data.scroll_update.inertial_phase =
+ blink::WebGestureEvent::kMomentumPhase;
+ EXPECT_TRUE(controller_->FilterEventForSnap(update_event));
+
+ EXPECT_CALL(mock_client_, ScrollEndForSnapFling()).Times(1);
+ blink::WebGestureEvent begin_event(blink::WebInputEvent::kGestureScrollBegin,
+ 0, 0);
+ EXPECT_FALSE(controller_->FilterEventForSnap(begin_event));
+ testing::Mock::VerifyAndClearExpectations(&mock_client_);
+
+ EXPECT_FALSE(controller_->FilterEventForSnap(update_event));
+}
+
+} // namespace test
+} // namespace ui
diff --git a/chromium/ui/events/blink/snap_fling_curve.cc b/chromium/ui/events/blink/snap_fling_curve.cc
new file mode 100644
index 00000000000..f1fb6a1eb5f
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_curve.cc
@@ -0,0 +1,119 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/blink/snap_fling_curve.h"
+
+#include <cmath>
+#include "build/build_config.h"
+
+namespace ui {
+namespace {
+
+#if defined(OS_ANDROID)
+constexpr double kDistanceEstimatorScalar = 40;
+// The delta to be scrolled in next frame is 0.9 of the delta in last frame.
+constexpr double kRatio = 0.9;
+#else
+constexpr double kDistanceEstimatorScalar = 25;
+// The delta to be scrolled in next frame is 0.92 of the delta in last frame.
+constexpr double kRatio = 0.92;
+#endif
+constexpr double kMsPerFrame = 16;
+constexpr base::TimeDelta kMaximumSnapDuration =
+ base::TimeDelta::FromSecondsD(5);
+
+double GetDistanceFromDisplacement(gfx::Vector2dF displacement) {
+ return std::hypot(displacement.x(), displacement.y());
+}
+
+double EstimateFramesFromDistance(double distance) {
+ // We approximate scroll deltas as a geometric sequence with the ratio kRatio,
+ // and the last scrolled delta should be less or equal than 1, yielding the
+ // total distance as (1 - kRatio^(-n)) / (1 - (1 / kRatio)). Solving this
+ // could get n as below, which is the total number of deltas in the sequence,
+ // and is also the total frames needed to finish the curve.
+ return std::ceil(-std::log(1 - distance * (1 - 1 / kRatio)) /
+ std::log(kRatio));
+}
+
+double CalculateFirstDelta(double distance, double frames) {
+ // distance = first_delta (1 - kRatio^(frames) / (1 - kRatio)).
+ // We can get the |first_delta| by solving the equation above.
+ return distance * (1 - kRatio) / (1 - std::pow(kRatio, frames));
+}
+
+} // namespace
+
+gfx::Vector2dF SnapFlingCurve::EstimateDisplacement(
+ const gfx::Vector2dF& first_delta) {
+ gfx::Vector2dF destination = first_delta;
+ destination.Scale(kDistanceEstimatorScalar);
+ return destination;
+}
+
+SnapFlingCurve::SnapFlingCurve(const gfx::Vector2dF& start_offset,
+ const gfx::Vector2dF& target_offset,
+ base::TimeTicks first_gsu_time)
+ : start_offset_(start_offset),
+ total_displacement_(target_offset - start_offset),
+ total_distance_(GetDistanceFromDisplacement(total_displacement_)),
+ start_time_(first_gsu_time),
+ total_frames_(EstimateFramesFromDistance(total_distance_)),
+ first_delta_(CalculateFirstDelta(total_distance_, total_frames_)),
+ duration_(base::TimeDelta::FromMilliseconds(total_frames_ * kMsPerFrame)),
+ is_finished_(total_distance_ == 0) {
+ if (is_finished_)
+ return;
+ ratio_x_ = total_displacement_.x() / total_distance_;
+ ratio_y_ = total_displacement_.y() / total_distance_;
+}
+
+SnapFlingCurve::~SnapFlingCurve() = default;
+
+double SnapFlingCurve::GetCurrentCurveDistance(base::TimeTicks time_stamp) {
+ double current_distance = GetDistanceFromDisplacement(current_displacement_);
+ base::TimeDelta current_time = time_stamp - start_time_;
+
+ // Finishes the curve if the time elapsed is longer than |duration_|, or the
+ // remaining distance is less than 1.
+ if (current_time >= duration_ || current_distance >= total_distance_ - 1) {
+ return total_distance_;
+ }
+
+ double current_frame = current_time.InMillisecondsF() / kMsPerFrame + 1;
+ double sum =
+ first_delta_ * (1 - std::pow(kRatio, current_frame)) / (1 - kRatio);
+ return sum <= total_distance_ ? sum : total_distance_;
+}
+
+gfx::Vector2dF SnapFlingCurve::GetScrollDelta(base::TimeTicks time_stamp) {
+ if (is_finished_)
+ return gfx::Vector2dF();
+
+ // The the snap offset may never be reached due to clamping or other factors.
+ // To avoid a never ending snap curve, we force the curve to end if the time
+ // has passed a maximum Duration.
+ if (time_stamp - start_time_ > kMaximumSnapDuration) {
+ is_finished_ = true;
+ return total_displacement_ - current_displacement_;
+ }
+
+ double new_distance = GetCurrentCurveDistance(time_stamp);
+ gfx::Vector2dF new_displacement(new_distance * ratio_x_,
+ new_distance * ratio_y_);
+
+ return new_displacement - current_displacement_;
+}
+
+void SnapFlingCurve::UpdateCurrentOffset(const gfx::Vector2dF& current_offset) {
+ current_displacement_ = current_offset - start_offset_;
+ if (current_displacement_ == total_displacement_)
+ is_finished_ = true;
+}
+
+bool SnapFlingCurve::IsFinished() const {
+ return is_finished_;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/blink/snap_fling_curve.h b/chromium/ui/events/blink/snap_fling_curve.h
new file mode 100644
index 00000000000..28d6adbcff7
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_curve.h
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_BLINK_SNAP_FLING_CURVE_H_
+#define UI_EVENTS_BLINK_SNAP_FLING_CURVE_H_
+
+#include "base/time/time.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace ui {
+
+// The curve for the snap fling animation. The curve would generate a geometric
+// sequence of deltas to be scrolled at each frame.
+class SnapFlingCurve {
+ public:
+ // Creates the curve based on the start offset, target offset, and the first
+ // inertial GSU's time_stamp.
+ SnapFlingCurve(const gfx::Vector2dF& start_offset,
+ const gfx::Vector2dF& target_offset,
+ base::TimeTicks first_gsu_time);
+
+ virtual ~SnapFlingCurve();
+
+ // Estimate the total distance that will be scrolled given the first GSU's
+ // delta
+ static gfx::Vector2dF EstimateDisplacement(const gfx::Vector2dF& first_delta);
+
+ // Returns the delta that should be scrolled at |time|.
+ virtual gfx::Vector2dF GetScrollDelta(base::TimeTicks time);
+
+ // Updates |current_displacement_|. This sync is necessary because the node
+ // might be scrolled by other calls and the scrolls might be clamped.
+ void UpdateCurrentOffset(const gfx::Vector2dF& current_offset);
+
+ // Returns true if the scroll has arrived at the snap destination.
+ virtual bool IsFinished() const;
+
+ base::TimeDelta duration() const { return duration_; }
+
+ private:
+ // Returns the curve's current distance at |time_stamp|.
+ double GetCurrentCurveDistance(base::TimeTicks time_stamp);
+
+ // The initial scroll offset of the scroller.
+ const gfx::Vector2dF start_offset_;
+
+ // The total displacement to the snap position.
+ const gfx::Vector2dF total_displacement_;
+ // 1D representation of |total_displacement_|.
+ const double total_distance_;
+
+ // The current displacement that has been scrolled.
+ gfx::Vector2dF current_displacement_;
+
+ // The timestamp of the first GSU.
+ const base::TimeTicks start_time_;
+
+ // The number of deltas in the curve's geometric sequence.
+ const double total_frames_;
+ // The first delta that defines the curve's geometric sequence.
+ const double first_delta_;
+ // The total milliseconds needed to finish the curve.
+ const base::TimeDelta duration_;
+
+ bool is_finished_ = false;
+
+ // |total_displacement_.x| / |total_distance_|
+ double ratio_x_;
+ // |total_displacement_.y| / |total_distance_|
+ double ratio_y_;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_BLINK_SNAP_FLING_CURVE_H_
diff --git a/chromium/ui/events/blink/snap_fling_curve_unittest.cc b/chromium/ui/events/blink/snap_fling_curve_unittest.cc
new file mode 100644
index 00000000000..2c1666e3891
--- /dev/null
+++ b/chromium/ui/events/blink/snap_fling_curve_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/blink/snap_fling_curve.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace test {
+
+TEST(SnapFlingCurveTest, CurveInitialization) {
+ SnapFlingCurve active_curve(gfx::Vector2dF(100, 100),
+ gfx::Vector2dF(500, 500), base::TimeTicks());
+ EXPECT_FALSE(active_curve.IsFinished());
+
+ SnapFlingCurve finished_curve(gfx::Vector2dF(100, 100),
+ gfx::Vector2dF(100, 100), base::TimeTicks());
+ EXPECT_TRUE(finished_curve.IsFinished());
+}
+
+TEST(SnapFlingCurveTest, AdvanceHalfwayThrough) {
+ SnapFlingCurve curve(gfx::Vector2dF(100, 100), gfx::Vector2dF(500, 500),
+ base::TimeTicks());
+ base::TimeDelta duration = curve.duration();
+ gfx::Vector2dF delta1 =
+ curve.GetScrollDelta(base::TimeTicks() + duration / 2);
+ EXPECT_LT(0, delta1.x());
+ EXPECT_LT(0, delta1.y());
+ EXPECT_FALSE(curve.IsFinished());
+
+ // Repeated offset computations at the same timestamp before applying the
+ // scrolled delta should yield identical results.
+ gfx::Vector2dF delta2 =
+ curve.GetScrollDelta(base::TimeTicks() + duration / 2);
+ EXPECT_EQ(delta1, delta2);
+ EXPECT_FALSE(curve.IsFinished());
+
+ curve.UpdateCurrentOffset(gfx::Vector2dF(100, 100) + delta1);
+ EXPECT_FALSE(curve.IsFinished());
+}
+
+TEST(SnapFlingCurveTest, AdvanceFullyThroughOnlyFinishesAfterUpdate) {
+ SnapFlingCurve curve(gfx::Vector2dF(100, 100), gfx::Vector2dF(500, 500),
+ base::TimeTicks());
+ gfx::Vector2dF delta =
+ curve.GetScrollDelta(base::TimeTicks() + curve.duration());
+ EXPECT_EQ(gfx::Vector2dF(400, 400), delta);
+ EXPECT_FALSE(curve.IsFinished());
+
+ curve.UpdateCurrentOffset(gfx::Vector2dF(500, 500));
+ EXPECT_TRUE(curve.IsFinished());
+}
+
+TEST(SnapFlingCurveTest, ReturnsZeroAfterFinished) {
+ SnapFlingCurve curve(gfx::Vector2dF(100, 100), gfx::Vector2dF(500, 500),
+ base::TimeTicks());
+ curve.UpdateCurrentOffset(gfx::Vector2dF(500, 500));
+ EXPECT_TRUE(curve.IsFinished());
+
+ gfx::Vector2dF delta = curve.GetScrollDelta(base::TimeTicks());
+ EXPECT_EQ(gfx::Vector2dF(), delta);
+ EXPECT_TRUE(curve.IsFinished());
+
+ delta = curve.GetScrollDelta(base::TimeTicks() + curve.duration());
+ EXPECT_EQ(gfx::Vector2dF(), delta);
+ EXPECT_TRUE(curve.IsFinished());
+}
+
+} // namespace test
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/events/blink/web_input_event.cc b/chromium/ui/events/blink/web_input_event.cc
index 94015fbaeb0..b88916cae8f 100644
--- a/chromium/ui/events/blink/web_input_event.cc
+++ b/chromium/ui/events/blink/web_input_event.cc
@@ -68,7 +68,7 @@ blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
// construct our pre-translated events.
blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
- const base::NativeEvent& native_event,
+ const PlatformEvent& native_event,
const base::TimeTicks& time_stamp,
blink::WebPointerProperties::PointerType pointer_type) {
return WebMouseEventBuilder::Build(
@@ -77,7 +77,7 @@ blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
}
blink::WebMouseWheelEvent MakeUntranslatedWebMouseWheelEventFromNativeEvent(
- const base::NativeEvent& native_event,
+ const PlatformEvent& native_event,
const base::TimeTicks& time_stamp,
blink::WebPointerProperties::PointerType pointer_type) {
return WebMouseWheelEventBuilder::Build(
@@ -149,6 +149,44 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
webkit_event.pointer_type =
EventPointerTypeToWebPointerType(event.pointer_details().pointer_type);
+
+ switch (event.scroll_event_phase()) {
+ case ui::ScrollEventPhase::kNone:
+ webkit_event.phase = blink::WebMouseWheelEvent::kPhaseNone;
+ break;
+ case ui::ScrollEventPhase::kBegan:
+ webkit_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ break;
+ case ui::ScrollEventPhase::kUpdate:
+ webkit_event.phase = blink::WebMouseWheelEvent::kPhaseChanged;
+ break;
+ case ui::ScrollEventPhase::kEnd:
+ webkit_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ switch (event.momentum_phase()) {
+ case ui::EventMomentumPhase::NONE:
+ webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseNone;
+ break;
+ case ui::EventMomentumPhase::BEGAN:
+ webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ break;
+ case ui::EventMomentumPhase::MAY_BEGIN:
+ webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseMayBegin;
+ break;
+ case ui::EventMomentumPhase::INERTIAL_UPDATE:
+ webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseChanged;
+ break;
+ case ui::EventMomentumPhase::END:
+ webkit_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseEnded;
+ break;
+ default:
+ NOTREACHED();
+ }
+
return webkit_event;
}
@@ -171,8 +209,8 @@ blink::WebGestureEvent MakeWebGestureEventFromUiEvent(
blink::WebGestureEvent webkit_event(
type, EventFlagsToWebEventModifiers(event.flags()),
- EventTimeStampToSeconds(event.time_stamp()));
- webkit_event.source_device = blink::kWebGestureDeviceTouchpad;
+ EventTimeStampToSeconds(event.time_stamp()),
+ blink::kWebGestureDeviceTouchpad);
if (event.type() == ET_SCROLL_FLING_START) {
webkit_event.data.fling_start.velocity_x = event.x_offset();
webkit_event.data.fling_start.velocity_y = event.y_offset();
@@ -193,13 +231,13 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
// information cleanly and consistently.
//
// The only place where an Event's data differs from what the underlying
-// base::NativeEvent would provide is position data. We would like to provide
+// PlatformEvent would provide is position data. We would like to provide
// coordinates relative to its hosting window, rather than the top level
// platform window. To do this a callback is accepted to allow for clients to
// map the coordinates.
//
// The approach is to fully construct a blink::WebInputEvent from the
-// Event's base::NativeEvent, and then replace the coordinate fields with
+// Event's PlatformEvent, and then replace the coordinate fields with
// the translated values from the Event.
//
// The exception is mouse events on linux. The MouseEvent contains enough
@@ -312,7 +350,7 @@ blink::WebKeyboardEvent MakeWebKeyboardEvent(const KeyEvent& event) {
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEventFromUiEvent(event);
#if defined(OS_WIN)
if (event.HasNativeEvent()) {
- const base::NativeEvent& native_event = event.native_event();
+ const PlatformEvent& native_event = event.native_event();
// System key events are explicitly distinguished, under Windows.
webkit_event.is_system_key = native_event.message == WM_SYSCHAR ||
@@ -332,13 +370,11 @@ blink::WebGestureEvent MakeWebGestureEvent(
screen_location_callback) {
blink::WebGestureEvent gesture_event = MakeWebGestureEventFromUIEvent(event);
- gesture_event.x = event.x();
- gesture_event.y = event.y();
+ gesture_event.SetPositionInWidget(event.location_f());
const gfx::PointF screen_point =
GetScreenLocationFromEvent(event, screen_location_callback);
- gesture_event.global_x = screen_point.x();
- gesture_event.global_y = screen_point.y();
+ gesture_event.SetPositionInScreen(screen_point);
return gesture_event;
}
@@ -348,13 +384,11 @@ blink::WebGestureEvent MakeWebGestureEvent(
const base::Callback<gfx::PointF(const LocatedEvent& event)>&
screen_location_callback) {
blink::WebGestureEvent gesture_event = MakeWebGestureEventFromUiEvent(event);
- gesture_event.x = event.x();
- gesture_event.y = event.y();
+ gesture_event.SetPositionInWidget(event.location_f());
const gfx::PointF screen_point =
GetScreenLocationFromEvent(event, screen_location_callback);
- gesture_event.global_x = screen_point.x();
- gesture_event.global_y = screen_point.y();
+ gesture_event.SetPositionInScreen(screen_point);
return gesture_event;
}
@@ -363,10 +397,9 @@ blink::WebGestureEvent MakeWebGestureEventFlingCancel() {
blink::WebGestureEvent gesture_event(
blink::WebInputEvent::kGestureFlingCancel,
blink::WebInputEvent::kNoModifiers,
- EventTimeStampToSeconds(EventTimeForNow()));
-
+ EventTimeStampToSeconds(EventTimeForNow()),
+ blink::kWebGestureDeviceTouchpad);
// All other fields are ignored on a GestureFlingCancel event.
- gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
return gesture_event;
}
@@ -387,7 +420,7 @@ blink::WebMouseEvent MakeWebMouseEventFromUiEvent(const MouseEvent& event) {
// NotifyVirtual events are created for intermediate windows that the
// pointer crosses through. These occur when middle clicking.
// Change these into mouse move events.
- const base::NativeEvent& native_event = event.native_event();
+ const PlatformEvent& native_event = event.native_event();
if (native_event && native_event->type == LeaveNotify &&
native_event->xcrossing.detail == NotifyVirtual) {
@@ -464,6 +497,9 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromUiEvent(
webkit_event.delta_x = event.x_offset();
webkit_event.delta_y = event.y_offset();
+ if (event.flags() & ui::EF_PRECISION_SCROLLING_DELTA)
+ webkit_event.has_precise_scrolling_deltas = true;
+
webkit_event.wheel_ticks_x =
webkit_event.delta_x / MouseWheelEvent::kWheelDelta;
webkit_event.wheel_ticks_y =
diff --git a/chromium/ui/events/blink/web_input_event.h b/chromium/ui/events/blink/web_input_event.h
index 90d553e7695..58d024527cd 100644
--- a/chromium/ui/events/blink/web_input_event.h
+++ b/chromium/ui/events/blink/web_input_event.h
@@ -6,11 +6,11 @@
#define UI_EVENTS_BLINK_WEB_INPUT_EVENT_H_
#include "base/callback.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_keyboard_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
namespace ui {
class GestureEvent;
diff --git a/chromium/ui/events/blink/web_input_event_builders_win.h b/chromium/ui/events/blink/web_input_event_builders_win.h
index 8fc5b86681c..47c0afdfa74 100644
--- a/chromium/ui/events/blink/web_input_event_builders_win.h
+++ b/chromium/ui/events/blink/web_input_event_builders_win.h
@@ -7,9 +7,9 @@
#include <windows.h>
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_keyboard_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
namespace ui {
diff --git a/chromium/ui/events/blink/web_input_event_builders_win_unittest.cc b/chromium/ui/events/blink/web_input_event_builders_win_unittest.cc
index 61837d0dbf7..4ea7d84aa87 100644
--- a/chromium/ui/events/blink/web_input_event_builders_win_unittest.cc
+++ b/chromium/ui/events/blink/web_input_event_builders_win_unittest.cc
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/events/blink/web_input_event_builders_win.h"
#include "base/command_line.h"
#include "base/win/windows_version.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/display/display.h"
#include "ui/display/display_switches.h"
-#include "ui/events/blink/web_input_event_builders_win.h"
#include "ui/events/event_constants.h"
using blink::WebMouseEvent;
diff --git a/chromium/ui/events/blink/web_input_event_traits.cc b/chromium/ui/events/blink/web_input_event_traits.cc
index 6fc2c8718dc..917d99e96cc 100644
--- a/chromium/ui/events/blink/web_input_event_traits.cc
+++ b/chromium/ui/events/blink/web_input_event_traits.cc
@@ -6,10 +6,10 @@
#include "base/logging.h"
#include "base/strings/stringprintf.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_keyboard_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
using base::StringAppendF;
using base::SStringPrintf;
@@ -56,14 +56,16 @@ void ApppendEventDetails(const WebMouseWheelEvent& event, std::string* result) {
}
void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
- StringAppendF(
- result,
- "{\n Pos: (%d, %d)\n GlobalPos: (%d, %d)\n SourceDevice: %d\n"
- " RawData: (%f, %f, %f, %f, %d)\n}",
- event.x, event.y, event.global_x, event.global_y, event.source_device,
- event.data.scroll_update.delta_x, event.data.scroll_update.delta_y,
- event.data.scroll_update.velocity_x, event.data.scroll_update.velocity_y,
- event.data.scroll_update.previous_update_in_sequence_prevented);
+ StringAppendF(result,
+ "{\n Pos: (%f, %f)\n GlobalPos: (%f, %f)\n SourceDevice: %d\n"
+ " RawData: (%f, %f, %f, %f, %d)\n}",
+ event.PositionInWidget().x, event.PositionInWidget().y,
+ event.PositionInScreen().x, event.PositionInScreen().y,
+ event.SourceDevice(), event.data.scroll_update.delta_x,
+ event.data.scroll_update.delta_y,
+ event.data.scroll_update.velocity_x,
+ event.data.scroll_update.velocity_y,
+ event.data.scroll_update.previous_update_in_sequence_prevented);
}
void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) {
@@ -247,10 +249,10 @@ uint32_t WebInputEventTraits::GetUniqueTouchEventId(
LatencyInfo WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(
const WebGestureEvent& event) {
SourceEventType source_event_type = SourceEventType::UNKNOWN;
- if (event.source_device ==
+ if (event.SourceDevice() ==
blink::WebGestureDevice::kWebGestureDeviceTouchpad) {
source_event_type = SourceEventType::WHEEL;
- } else if (event.source_device ==
+ } else if (event.SourceDevice() ==
blink::WebGestureDevice::kWebGestureDeviceTouchscreen) {
source_event_type = SourceEventType::TOUCH;
}
diff --git a/chromium/ui/events/blink/web_input_event_traits.h b/chromium/ui/events/blink/web_input_event_traits.h
index 94b2ad14b3a..fa3a7c13ad0 100644
--- a/chromium/ui/events/blink/web_input_event_traits.h
+++ b/chromium/ui/events/blink/web_input_event_traits.h
@@ -5,7 +5,7 @@
#ifndef UI_EVENTS_BLINK_WEB_INPUT_EVENT_TRAITS_H_
#define UI_EVENTS_BLINK_WEB_INPUT_EVENT_TRAITS_H_
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/latency/latency_info.h"
namespace blink {
diff --git a/chromium/ui/events/blink/web_input_event_traits_unittest.cc b/chromium/ui/events/blink/web_input_event_traits_unittest.cc
index a904dc421d6..f3d1d1b90b7 100644
--- a/chromium/ui/events/blink/web_input_event_traits_unittest.cc
+++ b/chromium/ui/events/blink/web_input_event_traits_unittest.cc
@@ -5,11 +5,11 @@
#include "ui/events/blink/web_input_event_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
-#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
-#include "third_party/WebKit/public/platform/WebTouchEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_keyboard_event.h"
+#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
using blink::WebGestureEvent;
using blink::WebInputEvent;
@@ -41,8 +41,7 @@ TEST_F(WebInputEventTraitsTest, ToString) {
WebGestureEvent gesture(WebInputEvent::kGesturePinchBegin,
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
- gesture.x = 1;
- gesture.y = 1;
+ gesture.SetPositionInWidget(gfx::PointF(1, 1));
EXPECT_FALSE(WebInputEventTraits::ToString(gesture).empty());
WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
diff --git a/chromium/ui/events/chromecast/OWNERS b/chromium/ui/events/chromecast/OWNERS
new file mode 100644
index 00000000000..16454c361a8
--- /dev/null
+++ b/chromium/ui/events/chromecast/OWNERS
@@ -0,0 +1,4 @@
+alexst@chromium.org
+kpschoedel@chromium.org
+rdaum@chromium.org
+spang@chromium.org
diff --git a/chromium/ui/events/chromecast/scroller.cc b/chromium/ui/events/chromecast/scroller.cc
index 9c989a95f10..0e2e2dcb4c8 100644
--- a/chromium/ui/events/chromecast/scroller.cc
+++ b/chromium/ui/events/chromecast/scroller.cc
@@ -186,7 +186,7 @@ Scroller::Scroller(const Config& config)
distance_(0),
fling_friction_(config.fling_friction),
deceleration_(ComputeDeceleration(fling_friction_)),
- tuning_coeff_(ComputeDeceleration(0.84f)) {
+ tuning_coeff_(ComputeDeceleration(3.25f)) {
}
Scroller::~Scroller() {
diff --git a/chromium/ui/events/cocoa/events_mac.mm b/chromium/ui/events/cocoa/events_mac.mm
index a0280c53dc3..4825cb9270e 100644
--- a/chromium/ui/events/cocoa/events_mac.mm
+++ b/chromium/ui/events/cocoa/events_mac.mm
@@ -21,7 +21,7 @@
namespace ui {
-EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
NSEventType type = [native_event type];
switch (type) {
case NSKeyDown:
@@ -72,19 +72,19 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
return ET_UNKNOWN;
}
-int EventFlagsFromNative(const base::NativeEvent& event) {
+int EventFlagsFromNative(const PlatformEvent& event) {
NSUInteger modifiers = [event modifierFlags];
return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
-base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
base::TimeTicks timestamp =
ui::EventTimeStampFromSeconds([native_event timestamp]);
ValidateEventTimeClock(&timestamp);
return timestamp;
}
-gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
NSWindow* window = [native_event window];
if (!window) {
NOTIMPLEMENTED(); // Point will be in screen coordinates.
@@ -95,19 +95,17 @@ gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
return gfx::PointF(location.x, NSHeight(content_rect) - location.y);
}
-gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event) {
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return gfx::Point();
}
-int EventButtonFromNative(const base::NativeEvent& native_event) {
+int EventButtonFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
-int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event) {
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
NSEventType type = [native_event type];
switch (type) {
case NSLeftMouseDown:
@@ -129,11 +127,11 @@ int GetChangedMouseButtonFlagsFromNative(
}
PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
return PointerDetails(EventPointerType::POINTER_TYPE_MOUSE);
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& event) {
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& event) {
if ([event hasPreciseScrollingDeltas]) {
// Handle continuous scrolling devices such as a Magic Mouse or a trackpad.
// -scrollingDelta{X|Y} have float return types but they return values that
@@ -154,25 +152,25 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& event) {
}
}
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+PlatformEvent CopyNativeEvent(const PlatformEvent& event) {
return [event copy];
}
-void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+void ReleaseCopiedNativeEvent(const PlatformEvent& event) {
[event release];
}
-void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
+void ClearTouchIdIfReleased(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
}
-int GetTouchId(const base::NativeEvent& native_event) {
+int GetTouchId(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
PointerDetails GetTouchPointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return PointerDetails(EventPointerType::POINTER_TYPE_UNKNOWN,
/* pointer_id*/ 0,
@@ -181,7 +179,7 @@ PointerDetails GetTouchPointerDetailsFromNative(
/* force */ 0.f);
}
-bool GetScrollOffsets(const base::NativeEvent& native_event,
+bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -230,7 +228,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
return true;
}
-bool GetFlingData(const base::NativeEvent& native_event,
+bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
@@ -240,19 +238,19 @@ bool GetFlingData(const base::NativeEvent& native_event,
return false;
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
return KeyboardCodeFromNSEvent(native_event);
}
-DomCode CodeFromNative(const base::NativeEvent& native_event) {
+DomCode CodeFromNative(const PlatformEvent& native_event) {
return DomCodeFromNSEvent(native_event);
}
-uint32_t WindowsKeycodeFromNative(const base::NativeEvent& native_event) {
+uint32_t WindowsKeycodeFromNative(const PlatformEvent& native_event) {
return static_cast<uint32_t>(KeyboardCodeFromNSEvent(native_event));
}
-uint16_t TextFromNative(const base::NativeEvent& native_event) {
+uint16_t TextFromNative(const PlatformEvent& native_event) {
NSString* text = @"";
if ([native_event type] != NSFlagsChanged)
text = [native_event characters];
@@ -271,7 +269,7 @@ uint16_t TextFromNative(const base::NativeEvent& native_event) {
return return_value;
}
-uint16_t UnmodifiedTextFromNative(const base::NativeEvent& native_event) {
+uint16_t UnmodifiedTextFromNative(const PlatformEvent& native_event) {
NSString* text = @"";
if ([native_event type] != NSFlagsChanged)
text = [native_event charactersIgnoringModifiers];
@@ -290,7 +288,7 @@ uint16_t UnmodifiedTextFromNative(const base::NativeEvent& native_event) {
return return_value;
}
-bool IsCharFromNative(const base::NativeEvent& native_event) {
+bool IsCharFromNative(const PlatformEvent& native_event) {
return false;
}
diff --git a/chromium/ui/events/devices/BUILD.gn b/chromium/ui/events/devices/BUILD.gn
index 2caa514ba6c..ed92538f45f 100644
--- a/chromium/ui/events/devices/BUILD.gn
+++ b/chromium/ui/events/devices/BUILD.gn
@@ -44,6 +44,7 @@ jumbo_component("devices") {
"//base",
"//base/third_party/dynamic_annotations",
"//skia",
+ "//ui/events:platform_event",
"//ui/gfx:geometry_skia",
"//ui/gfx/geometry",
]
diff --git a/chromium/ui/events/devices/input_device.cc b/chromium/ui/events/devices/input_device.cc
index b60f85a0a15..e85ee1ec2d2 100644
--- a/chromium/ui/events/devices/input_device.cc
+++ b/chromium/ui/events/devices/input_device.cc
@@ -24,12 +24,14 @@ InputDevice::InputDevice(int id, InputDeviceType type, const std::string& name)
InputDevice::InputDevice(int id,
InputDeviceType type,
const std::string& name,
+ const std::string& phys,
const base::FilePath& sys_path,
uint16_t vendor,
uint16_t product)
: id(id),
type(type),
name(name),
+ phys(phys),
sys_path(sys_path),
vendor_id(vendor),
product_id(product) {}
diff --git a/chromium/ui/events/devices/input_device.h b/chromium/ui/events/devices/input_device.h
index f048fcc2f90..f97154d9f49 100644
--- a/chromium/ui/events/devices/input_device.h
+++ b/chromium/ui/events/devices/input_device.h
@@ -30,6 +30,7 @@ struct EVENTS_DEVICES_EXPORT InputDevice {
InputDevice(int id,
InputDeviceType type,
const std::string& name,
+ const std::string& phys,
const base::FilePath& sys_path,
uint16_t vendor,
uint16_t product);
@@ -45,6 +46,12 @@ struct EVENTS_DEVICES_EXPORT InputDevice {
// Name of the device.
std::string name;
+ // The physical location(port) associated with the input device. This is
+ // (supposed to be) stable between reboots and hotplugs. However this may not
+ // always be set and will change when the device is connected via a different
+ // port.
+ std::string phys;
+
// If the device is enabled, and whether events should be dispatched to UI.
bool enabled = true;
diff --git a/chromium/ui/events/devices/x11/device_data_manager_x11.h b/chromium/ui/events/devices/x11/device_data_manager_x11.h
index b26132763ca..daadcb877bd 100644
--- a/chromium/ui/events/devices/x11/device_data_manager_x11.h
+++ b/chromium/ui/events/devices/x11/device_data_manager_x11.h
@@ -12,12 +12,12 @@
#include <set>
#include <vector>
-#include "base/event_types.h"
#include "base/macros.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/x11/events_devices_x11_export.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc
index 68daf98868e..d8c1fb39e49 100644
--- a/chromium/ui/events/event.cc
+++ b/chromium/ui/events/event.cc
@@ -179,16 +179,8 @@ SourceEventType EventTypeToLatencySourceEventType(EventType type) {
return SourceEventType::UNKNOWN;
}
-bool IsX11SendEventTrue(const base::NativeEvent& event) {
#if defined(USE_X11)
- return event && event->xany.send_event;
-#else
- return false;
-#endif
-}
-
-#if defined(USE_X11)
-bool X11EventHasNonStandardState(const base::NativeEvent& event) {
+bool X11EventHasNonStandardState(const PlatformEvent& event) {
const unsigned int kAllStateMask =
Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
@@ -198,6 +190,11 @@ bool X11EventHasNonStandardState(const base::NativeEvent& event) {
}
#endif
+constexpr int kChangedButtonFlagMask =
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON |
+ ui::EF_RIGHT_MOUSE_BUTTON | ui::EF_BACK_MOUSE_BUTTON |
+ ui::EF_FORWARD_MOUSE_BUTTON;
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -357,7 +354,7 @@ const TouchEvent* Event::AsTouchEvent() const {
}
bool Event::HasNativeEvent() const {
- base::NativeEvent null_event;
+ PlatformEvent null_event;
std::memset(&null_event, 0, sizeof(null_event));
return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
}
@@ -382,7 +379,7 @@ Event::Event(EventType type, base::TimeTicks time_stamp, int flags)
: type_(type),
time_stamp_(time_stamp),
flags_(flags),
- native_event_(base::NativeEvent()),
+ native_event_(PlatformEvent()),
delete_native_event_(false),
cancelable_(true),
target_(NULL),
@@ -393,9 +390,7 @@ Event::Event(EventType type, base::TimeTicks time_stamp, int flags)
latency()->set_source_event_type(EventTypeToLatencySourceEventType(type));
}
-Event::Event(const base::NativeEvent& native_event,
- EventType type,
- int flags)
+Event::Event(const PlatformEvent& native_event, EventType type, int flags)
: type_(type),
time_stamp_(EventTimeFromNative(native_event)),
flags_(flags),
@@ -459,7 +454,7 @@ CancelModeEvent::~CancelModeEvent() {
LocatedEvent::~LocatedEvent() = default;
-LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
+LocatedEvent::LocatedEvent(const PlatformEvent& native_event)
: Event(native_event,
EventTypeFromNative(native_event),
EventFlagsFromNative(native_event)),
@@ -550,7 +545,7 @@ const PointerId PointerDetails::kUnknownPointerId = -1;
////////////////////////////////////////////////////////////////////////////////
// MouseEvent
-MouseEvent::MouseEvent(const base::NativeEvent& native_event)
+MouseEvent::MouseEvent(const PlatformEvent& native_event)
: LocatedEvent(native_event),
changed_button_flags_(GetChangedMouseButtonFlagsFromNative(native_event)),
pointer_details_(GetMousePointerDetailsFromNative(native_event)) {
@@ -624,6 +619,8 @@ MouseEvent::MouseEvent(EventType type,
changed_button_flags_(changed_button_flags),
pointer_details_(pointer_details) {
DCHECK_NE(ET_MOUSEWHEEL, type);
+ DCHECK_EQ(changed_button_flags_,
+ changed_button_flags_ & kChangedButtonFlagMask);
latency()->set_source_event_type(ui::SourceEventType::MOUSE);
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
@@ -635,9 +632,8 @@ MouseEvent::MouseEvent(const MouseEvent& other) = default;
MouseEvent::~MouseEvent() = default;
// static
-bool MouseEvent::IsRepeatedClickEvent(
- const MouseEvent& event1,
- const MouseEvent& event2) {
+bool MouseEvent::IsRepeatedClickEvent(const MouseEvent& event1,
+ const MouseEvent& event2) {
// These values match the Windows defaults.
static const int kDoubleClickTimeMS = 500;
static const int kDoubleClickWidth = 4;
@@ -677,7 +673,6 @@ int MouseEvent::GetRepeatCount(const MouseEvent& event) {
if (event.type() == ui::ET_MOUSE_RELEASED) {
if (event.changed_button_flags() ==
last_click_event_->changed_button_flags()) {
- last_click_complete_ = true;
return last_click_event_->GetClickCount();
} else {
// If last_click_event_ has changed since this button was pressed
@@ -685,18 +680,15 @@ int MouseEvent::GetRepeatCount(const MouseEvent& event) {
return click_count;
}
}
- if (event.time_stamp() != last_click_event_->time_stamp())
- last_click_complete_ = true;
- if (!last_click_complete_ ||
- IsX11SendEventTrue(event.native_event())) {
- click_count = last_click_event_->GetClickCount();
- } else if (IsRepeatedClickEvent(*last_click_event_, event)) {
+ // Return the prior click count and do not update |last_click_event_| when
+ // re-processing a native event, or when proccesing a reposted event.
+ if (event.time_stamp() == last_click_event_->time_stamp())
+ return last_click_event_->GetClickCount();
+ if (IsRepeatedClickEvent(*last_click_event_, event))
click_count = last_click_event_->GetClickCount() + 1;
- }
delete last_click_event_;
}
last_click_event_ = new MouseEvent(event);
- last_click_complete_ = false;
if (click_count > 3)
click_count = 3;
last_click_event_->SetClickCount(click_count);
@@ -707,13 +699,11 @@ void MouseEvent::ResetLastClickForTest() {
if (last_click_event_) {
delete last_click_event_;
last_click_event_ = NULL;
- last_click_complete_ = false;
}
}
// static
MouseEvent* MouseEvent::last_click_event_ = NULL;
-bool MouseEvent::last_click_complete_ = false;
int MouseEvent::GetClickCount() const {
if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
@@ -758,10 +748,8 @@ const PointerId MouseEvent::kMousePointerId =
////////////////////////////////////////////////////////////////////////////////
// MouseWheelEvent
-MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
- : MouseEvent(native_event),
- offset_(GetMouseWheelOffset(native_event)) {
-}
+MouseWheelEvent::MouseWheelEvent(const PlatformEvent& native_event)
+ : MouseEvent(native_event), offset_(GetMouseWheelOffset(native_event)) {}
MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
: MouseEvent(scroll_event),
@@ -823,7 +811,7 @@ const int MouseWheelEvent::kWheelDelta = 53;
////////////////////////////////////////////////////////////////////////////////
// TouchEvent
-TouchEvent::TouchEvent(const base::NativeEvent& native_event)
+TouchEvent::TouchEvent(const PlatformEvent& native_event)
: LocatedEvent(native_event),
unique_event_id_(ui::GetNextTouchEventId()),
may_cause_scrolling_(false),
@@ -1160,10 +1148,10 @@ bool KeyEvent::IsRepeated(const KeyEvent& event) {
return false;
}
-KeyEvent::KeyEvent(const base::NativeEvent& native_event)
+KeyEvent::KeyEvent(const PlatformEvent& native_event)
: KeyEvent(native_event, EventFlagsFromNative(native_event)) {}
-KeyEvent::KeyEvent(const base::NativeEvent& native_event, int event_flags)
+KeyEvent::KeyEvent(const PlatformEvent& native_event, int event_flags)
: Event(native_event, EventTypeFromNative(native_event), event_flags),
key_code_(KeyboardCodeFromNative(native_event)),
code_(CodeFromNative(native_event)),
@@ -1410,14 +1398,15 @@ std::string KeyEvent::GetCodeString() const {
////////////////////////////////////////////////////////////////////////////////
// ScrollEvent
-ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
+ScrollEvent::ScrollEvent(const PlatformEvent& native_event)
: MouseEvent(native_event),
x_offset_(0.0f),
y_offset_(0.0f),
x_offset_ordinal_(0.0f),
y_offset_ordinal_(0.0f),
finger_count_(0),
- momentum_phase_(EventMomentumPhase::NONE) {
+ momentum_phase_(EventMomentumPhase::NONE),
+ scroll_event_phase_(ScrollEventPhase::kNone) {
if (type() == ET_SCROLL) {
GetScrollOffsets(native_event, &x_offset_, &y_offset_, &x_offset_ordinal_,
&y_offset_ordinal_, &finger_count_, &momentum_phase_);
@@ -1446,14 +1435,16 @@ ScrollEvent::ScrollEvent(EventType type,
float x_offset_ordinal,
float y_offset_ordinal,
int finger_count,
- EventMomentumPhase momentum_phase)
+ EventMomentumPhase momentum_phase,
+ ScrollEventPhase scroll_event_phase)
: MouseEvent(type, location, location, time_stamp, flags, 0),
x_offset_(x_offset),
y_offset_(y_offset),
x_offset_ordinal_(x_offset_ordinal),
y_offset_ordinal_(y_offset_ordinal),
finger_count_(finger_count),
- momentum_phase_(momentum_phase) {
+ momentum_phase_(momentum_phase),
+ scroll_event_phase_(scroll_event_phase) {
CHECK(IsScrollEvent());
latency()->set_source_event_type(ui::SourceEventType::WHEEL);
}
diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h
index 01fbde3ce9a..809840105b2 100644
--- a/chromium/ui/events/event.h
+++ b/chromium/ui/events/event.h
@@ -13,7 +13,6 @@
#include <vector>
#include "base/compiler_specific.h"
-#include "base/event_types.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -24,6 +23,7 @@
#include "ui/events/gestures/gesture_types.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/latency/latency_info.h"
@@ -77,7 +77,7 @@ class EVENTS_EXPORT Event {
DISALLOW_COPY_AND_ASSIGN(DispatcherApi);
};
- const base::NativeEvent& native_event() const { return native_event_; }
+ const PlatformEvent& native_event() const { return native_event_; }
EventType type() const { return type_; }
// time_stamp represents time since machine was booted.
const base::TimeTicks time_stamp() const { return time_stamp_; }
@@ -308,7 +308,7 @@ class EVENTS_EXPORT Event {
protected:
Event(EventType type, base::TimeTicks time_stamp, int flags);
- Event(const base::NativeEvent& native_event, EventType type, int flags);
+ Event(const PlatformEvent& native_event, EventType type, int flags);
Event(const Event& copy);
void SetType(EventType type);
void set_cancelable(bool cancelable) { cancelable_ = cancelable; }
@@ -324,7 +324,7 @@ class EVENTS_EXPORT Event {
base::TimeTicks time_stamp_;
LatencyInfo latency_;
int flags_;
- base::NativeEvent native_event_;
+ PlatformEvent native_event_;
bool delete_native_event_;
bool cancelable_;
EventTarget* target_;
@@ -394,7 +394,7 @@ class EVENTS_EXPORT LocatedEvent : public Event {
LocatedEvent(const LocatedEvent& copy);
- explicit LocatedEvent(const base::NativeEvent& native_event);
+ explicit LocatedEvent(const PlatformEvent& native_event);
// Create a new LocatedEvent which is identical to the provided model.
// If source / target windows are provided, the model location will be
@@ -506,8 +506,8 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
static const PointerId kMousePointerId;
// NOTE: On some platforms this will allow an event to be constructed from a
- // void*, see base::NativeEvent.
- explicit MouseEvent(const base::NativeEvent& native_event);
+ // void*, see PlatformEvent.
+ explicit MouseEvent(const PlatformEvent& native_event);
// |pointer_event.IsMousePointerEvent()| must be true.
// Note: If |pointer_event| is a mouse wheel pointer event, use the
@@ -614,7 +614,7 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
const PointerDetails& pointer_details() const { return pointer_details_; }
private:
- FRIEND_TEST_ALL_PREFIXES(EventTest, DoubleClickRequiresRelease);
+ FRIEND_TEST_ALL_PREFIXES(EventTest, DoubleClickRequiresUniqueTimestamp);
FRIEND_TEST_ALL_PREFIXES(EventTest, SingleClickRightLeft);
// Returns the repeat count based on the previous mouse click, if it is
@@ -627,13 +627,9 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
// See description above getter for details.
int changed_button_flags_;
+ // The most recent user-generated MouseEvent, used to detect double clicks.
static MouseEvent* last_click_event_;
- // We can create a MouseEvent for a native event more than once. We set this
- // to true when the next event either has a different timestamp or we see a
- // release signalling that the press (click) event was completed.
- static bool last_click_complete_;
-
// Structure for holding pointer details for implementing PointerEvents API.
PointerDetails pointer_details_;
};
@@ -645,7 +641,7 @@ class EVENTS_EXPORT MouseWheelEvent : public MouseEvent {
// See |offset| for details.
static const int kWheelDelta;
- explicit MouseWheelEvent(const base::NativeEvent& native_event);
+ explicit MouseWheelEvent(const PlatformEvent& native_event);
explicit MouseWheelEvent(const ScrollEvent& scroll_event);
explicit MouseWheelEvent(const PointerEvent& pointer_event);
MouseWheelEvent(const MouseEvent& mouse_event, int x_offset, int y_offset);
@@ -683,7 +679,7 @@ class EVENTS_EXPORT MouseWheelEvent : public MouseEvent {
// decided not to show hover effects for pen.
class EVENTS_EXPORT TouchEvent : public LocatedEvent {
public:
- explicit TouchEvent(const base::NativeEvent& native_event);
+ explicit TouchEvent(const PlatformEvent& native_event);
// |pointer_event.IsTouchPointerEvent()| must be true.
explicit TouchEvent(const PointerEvent& pointer_event);
@@ -836,11 +832,11 @@ class EVENTS_EXPORT KeyEvent : public Event {
// Create a KeyEvent from a NativeEvent. For Windows this native event can
// be either a keystroke message (WM_KEYUP/WM_KEYDOWN) or a character message
// (WM_CHAR). Other systems have only keystroke events.
- explicit KeyEvent(const base::NativeEvent& native_event);
+ explicit KeyEvent(const PlatformEvent& native_event);
// Create a KeyEvent from a NativeEvent but with mocked flags.
// This method is necessary for Windows since MSG does not contain all flags.
- KeyEvent(const base::NativeEvent& native_event, int event_flags);
+ KeyEvent(const PlatformEvent& native_event, int event_flags);
// Create a keystroke event from a legacy KeyboardCode.
// This should not be used in new code.
@@ -995,20 +991,18 @@ class EVENTS_EXPORT KeyEvent : public Event {
class EVENTS_EXPORT ScrollEvent : public MouseEvent {
public:
- explicit ScrollEvent(const base::NativeEvent& native_event);
+ explicit ScrollEvent(const PlatformEvent& native_event);
template <class T>
- ScrollEvent(const ScrollEvent& model,
- T* source,
- T* target)
+ ScrollEvent(const ScrollEvent& model, T* source, T* target)
: MouseEvent(model, source, target),
x_offset_(model.x_offset_),
y_offset_(model.y_offset_),
x_offset_ordinal_(model.x_offset_ordinal_),
y_offset_ordinal_(model.y_offset_ordinal_),
- finger_count_(model.finger_count_){
- }
+ finger_count_(model.finger_count_),
+ momentum_phase_(model.momentum_phase_),
+ scroll_event_phase_(model.scroll_event_phase_) {}
- // Used for tests.
ScrollEvent(EventType type,
const gfx::Point& location,
base::TimeTicks time_stamp,
@@ -1018,7 +1012,8 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
float x_offset_ordinal,
float y_offset_ordinal,
int finger_count,
- EventMomentumPhase momentum_phase = EventMomentumPhase::NONE);
+ EventMomentumPhase momentum_phase = EventMomentumPhase::NONE,
+ ScrollEventPhase phase = ScrollEventPhase::kNone);
ScrollEvent(const ScrollEvent& copy);
~ScrollEvent() override;
@@ -1034,6 +1029,7 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
float y_offset_ordinal() const { return y_offset_ordinal_; }
int finger_count() const { return finger_count_; }
EventMomentumPhase momentum_phase() const { return momentum_phase_; }
+ ScrollEventPhase scroll_event_phase() const { return scroll_event_phase_; }
private:
// Potential accelerated offsets.
@@ -1047,7 +1043,10 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
// For non-fling events, provides momentum information (e.g. for the case
// where the device provides continuous event updates during a fling).
- EventMomentumPhase momentum_phase_;
+ EventMomentumPhase momentum_phase_ = EventMomentumPhase::NONE;
+
+ // Provides phase information if device can provide.
+ ScrollEventPhase scroll_event_phase_ = ScrollEventPhase::kNone;
};
class EVENTS_EXPORT GestureEvent : public LocatedEvent {
diff --git a/chromium/ui/events/event_constants.h b/chromium/ui/events/event_constants.h
index 9340ec0b28f..90c04152f9a 100644
--- a/chromium/ui/events/event_constants.h
+++ b/chromium/ui/events/event_constants.h
@@ -139,6 +139,9 @@ enum MouseEventFlags {
EF_CURSOR_HIDE = 1 << 20, // Indicates this mouse event is generated
// because the cursor was just hidden. This
// can be used to update hover state.
+ EF_PRECISION_SCROLLING_DELTA = // Indicates this mouse event is from high
+ 1 << 21, // precision touchpad and will come with a
+ // high precision delta.
};
// Result of dispatching an event.
@@ -165,12 +168,40 @@ enum EventPhase {
EP_POSTDISPATCH
};
+// Phase information used for a ScrollEvent. ScrollEventPhase is for scroll
+// stream from user gesture, EventMomentumPhase is for inertia scroll stream
+// after user gesture.
+enum class ScrollEventPhase {
+ // Event has no phase information. eg. the Event is not in a scroll stream.
+ kNone,
+
+ // Event is the beginning of a scroll event stream.
+ kBegan,
+
+ // Event is a scroll event with phase information.
+ kUpdate,
+
+ // Event is the end of the current scroll event stream.
+ kEnd,
+};
+
// Momentum phase information used for a ScrollEvent.
enum class EventMomentumPhase {
// Event is a non-momentum update to an event stream already begun.
NONE,
// Event is the beginning of an event stream that may result in momentum.
+ // BEGAN vs MAY_BEGIN:
+ // - BEGAN means we already know the inertia scroll stream must happen after
+ // BEGAN event. On Windows touchpad, we sent this when receive the first
+ // inertia scroll event or Direct Manipulation state change to INERTIA.
+ // - MAY_BEGIN means the inertia scroll stream may happen after MAY_BEGIN
+ // event. On Mac, we send this when receive releaseTouches, but we do not
+ // know the inertia scroll stream will happen or not at that time.
+ BEGAN,
+
+ // Event maybe the beginning of an event stream that may result in momentum.
+ // This state used on Mac.
MAY_BEGIN,
// Event is an update while in a momentum phase. A "begin" event for the
diff --git a/chromium/ui/events/event_rewriter_unittest.cc b/chromium/ui/events/event_rewriter_unittest.cc
index d649232fbbe..ae9abcea417 100644
--- a/chromium/ui/events/event_rewriter_unittest.cc
+++ b/chromium/ui/events/event_rewriter_unittest.cc
@@ -11,28 +11,14 @@
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/test_event_processor.h"
namespace ui {
namespace {
-// To test the handling of |EventRewriter|s through |EventSource|,
-// we rewrite and test event types.
-class TestEvent : public Event {
- public:
- explicit TestEvent(EventType type)
- : Event(type, base::TimeTicks(), 0), unique_id_(next_unique_id_++) {}
- ~TestEvent() override {}
- int unique_id() const { return unique_id_; }
-
- private:
- static int next_unique_id_;
- int unique_id_;
-};
-
-int TestEvent::next_unique_id_ = 0;
-
// TestEventRewriteProcessor is set up with a sequence of event types,
// and fails if the events received via OnEventFromSource() do not match
// this sequence. These expected event types are consumed on receipt.
@@ -58,6 +44,28 @@ class TestEventRewriteProcessor : public test::TestEventProcessor {
DISALLOW_COPY_AND_ASSIGN(TestEventRewriteProcessor);
};
+std::unique_ptr<Event> CreateEventForType(EventType type) {
+ switch (type) {
+ case ET_CANCEL_MODE:
+ return std::make_unique<CancelModeEvent>();
+ case ET_MOUSE_DRAGGED:
+ case ET_MOUSE_PRESSED:
+ case ET_MOUSE_RELEASED:
+ return std::make_unique<MouseEvent>(type, gfx::Point(), gfx::Point(),
+ base::TimeTicks::Now(), 0, 0);
+ case ET_KEY_PRESSED:
+ case ET_KEY_RELEASED:
+ return std::make_unique<KeyEvent>(type, ui::VKEY_TAB, DomCode::NONE, 0);
+ case ET_SCROLL_FLING_CANCEL:
+ case ET_SCROLL_FLING_START:
+ return std::make_unique<ScrollEvent>(
+ type, gfx::Point(), base::TimeTicks::Now(), 0, 0, 0, 0, 0, 0);
+ default:
+ NOTREACHED() << type;
+ return nullptr;
+ }
+}
+
// Trivial EventSource that does nothing but send events.
class TestEventRewriteSource : public EventSource {
public:
@@ -65,7 +73,7 @@ class TestEventRewriteSource : public EventSource {
: processor_(processor) {}
EventProcessor* GetEventSink() override { return processor_; }
void Send(EventType type) {
- std::unique_ptr<Event> event(new TestEvent(type));
+ auto event = CreateEventForType(type);
SendEventToSink(event.get());
}
@@ -88,7 +96,7 @@ class TestConstantEventRewriter : public EventRewriter {
const Event& event,
std::unique_ptr<Event>* rewritten_event) override {
if (status_ == EVENT_REWRITE_REWRITTEN)
- rewritten_event->reset(new TestEvent(type_));
+ *rewritten_event = CreateEventForType(type_);
return status_;
}
EventRewriteStatus NextDispatchEvent(
@@ -123,10 +131,10 @@ class TestStateMachineEventRewriter : public EventRewriter {
return EVENT_REWRITE_CONTINUE;
if ((find->second.status == EVENT_REWRITE_REWRITTEN) ||
(find->second.status == EVENT_REWRITE_DISPATCH_ANOTHER)) {
- last_rewritten_event_ = new TestEvent(find->second.type);
- rewritten_event->reset(last_rewritten_event_);
+ *rewritten_event = CreateEventForType(find->second.type);
+ last_rewritten_event_ = rewritten_event->get();
} else {
- last_rewritten_event_ = 0;
+ last_rewritten_event_ = nullptr;
}
state_ = find->second.state;
return find->second.status;
@@ -135,10 +143,8 @@ class TestStateMachineEventRewriter : public EventRewriter {
const Event& last_event,
std::unique_ptr<Event>* new_event) override {
EXPECT_TRUE(last_rewritten_event_);
- const TestEvent* arg_last = static_cast<const TestEvent*>(&last_event);
- EXPECT_EQ(last_rewritten_event_->unique_id(), arg_last->unique_id());
- const TestEvent* arg_new = static_cast<const TestEvent*>(new_event->get());
- EXPECT_FALSE(arg_new && arg_last->unique_id() == arg_new->unique_id());
+ EXPECT_EQ(last_rewritten_event_, &last_event);
+ EXPECT_FALSE(new_event->get() && new_event->get() == &last_event);
return RewriteEvent(last_event, new_event);
}
@@ -151,7 +157,7 @@ class TestStateMachineEventRewriter : public EventRewriter {
};
typedef std::map<RewriteCase, RewriteResult> RewriteRules;
RewriteRules rules_;
- TestEvent* last_rewritten_event_;
+ Event* last_rewritten_event_;
int state_;
};
diff --git a/chromium/ui/events/event_source.cc b/chromium/ui/events/event_source.cc
index fcdffe5dd1b..e45be7c97b4 100644
--- a/chromium/ui/events/event_source.cc
+++ b/chromium/ui/events/event_source.cc
@@ -11,6 +11,17 @@
#include "ui/events/event_sink.h"
namespace ui {
+namespace {
+
+bool IsLocatedEventWithDifferentLocations(const Event& event) {
+ if (!event.IsLocatedEvent())
+ return false;
+ const LocatedEvent* located_event = event.AsLocatedEvent();
+ return located_event->target() &&
+ located_event->location_f() != located_event->root_location_f();
+}
+
+} // namespace
EventSource::EventSource() {}
@@ -30,12 +41,23 @@ void EventSource::RemoveEventRewriter(EventRewriter* rewriter) {
}
EventDispatchDetails EventSource::SendEventToSink(Event* event) {
+ std::unique_ptr<ui::Event> event_for_rewriting_ptr;
+ Event* event_for_rewriting = event;
+ if (!rewriter_list_.empty() && IsLocatedEventWithDifferentLocations(*event)) {
+ // EventRewriters don't expect an event with differing location and
+ // root-location (because they don't honor the target). Provide such an
+ // event for rewriters.
+ event_for_rewriting_ptr = ui::Event::Clone(*event);
+ event_for_rewriting_ptr->AsLocatedEvent()->set_location_f(
+ event_for_rewriting_ptr->AsLocatedEvent()->root_location_f());
+ event_for_rewriting = event_for_rewriting_ptr.get();
+ }
std::unique_ptr<Event> rewritten_event;
EventRewriteStatus status = EVENT_REWRITE_CONTINUE;
EventRewriterList::const_iterator it = rewriter_list_.begin(),
end = rewriter_list_.end();
for (; it != end; ++it) {
- status = (*it)->RewriteEvent(*event, &rewritten_event);
+ status = (*it)->RewriteEvent(*event_for_rewriting, &rewritten_event);
if (status == EVENT_REWRITE_DISCARD) {
CHECK(!rewritten_event);
return EventDispatchDetails();
diff --git a/chromium/ui/events/event_target.cc b/chromium/ui/events/event_target.cc
index d2bdb4be4f0..bbd1422ba28 100644
--- a/chromium/ui/events/event_target.cc
+++ b/chromium/ui/events/event_target.cc
@@ -22,23 +22,43 @@ void EventTarget::ConvertEventToTarget(EventTarget* target,
LocatedEvent* event) {
}
-void EventTarget::AddPreTargetHandler(EventHandler* handler) {
+void EventTarget::AddPreTargetHandler(EventHandler* handler,
+ Priority priority) {
DCHECK(handler);
- pre_target_list_.push_back(handler);
-}
-
-void EventTarget::PrependPreTargetHandler(EventHandler* handler) {
- DCHECK(handler);
- pre_target_list_.insert(pre_target_list_.begin(), handler);
+ PrioritizedHandler prioritized = PrioritizedHandler();
+ prioritized.handler = handler;
+ prioritized.priority = priority;
+ EventHandlerPriorityList::iterator it;
+ switch (priority) {
+ case Priority::kDefault:
+ pre_target_list_.push_back(prioritized);
+ return;
+ case Priority::kSystem:
+ // Find the beginning of the kSystem part of the list and prepend
+ // this new handler to that section.
+ // TODO(katie): We are adding this to the front of the list because
+ // previously the function PrependPreTargetHandler added items to the
+ // front in this way. See if we can simply put each item in the list and
+ // sort, or insert each item the same way, in a later change.
+ it = std::lower_bound(pre_target_list_.begin(), pre_target_list_.end(),
+ prioritized);
+ pre_target_list_.insert(it, prioritized);
+ return;
+ case Priority::kAccessibility:
+ pre_target_list_.insert(pre_target_list_.begin(), prioritized);
+ return;
+ }
}
void EventTarget::RemovePreTargetHandler(EventHandler* handler) {
- EventHandlerList::iterator find =
- std::find(pre_target_list_.begin(),
- pre_target_list_.end(),
- handler);
- if (find != pre_target_list_.end())
- pre_target_list_.erase(find);
+ EventHandlerPriorityList::iterator it, end;
+ for (it = pre_target_list_.begin(), end = pre_target_list_.end(); it != end;
+ ++it) {
+ if (it->handler == handler) {
+ pre_target_list_.erase(it);
+ return;
+ }
+ }
}
void EventTarget::AddPostTargetHandler(EventHandler* handler) {
@@ -65,15 +85,18 @@ EventHandler* EventTarget::SetTargetHandler(EventHandler* target_handler) {
return original_target_handler;
}
+// TODO(katie): trigger all kAccessibility handlers in the tree first,
+// then kSystem and finally kDefault, rather than doing each set per
+// parent level.
void EventTarget::GetPreTargetHandlers(EventHandlerList* list) {
EventTarget* target = this;
while (target) {
- EventHandlerList::reverse_iterator it, rend;
+ EventHandlerPriorityList::reverse_iterator it, rend;
for (it = target->pre_target_list_.rbegin(),
rend = target->pre_target_list_.rend();
it != rend;
++it) {
- list->insert(list->begin(), *it);
+ list->insert(list->begin(), it->handler);
}
target = target->GetParentTarget();
}
diff --git a/chromium/ui/events/event_target.h b/chromium/ui/events/event_target.h
index 0d7328637ac..8b136fadc8c 100644
--- a/chromium/ui/events/event_target.h
+++ b/chromium/ui/events/event_target.h
@@ -26,10 +26,6 @@ class EVENTS_EXPORT EventTarget {
public:
explicit DispatcherApi(EventTarget* target) : target_(target) {}
- const EventHandlerList& pre_target_list() const {
- return target_->pre_target_list_;
- }
-
private:
DispatcherApi();
EventTarget* target_;
@@ -58,14 +54,26 @@ class EVENTS_EXPORT EventTarget {
virtual void ConvertEventToTarget(EventTarget* target,
LocatedEvent* event);
+ // Priority levels for PreTargetHandlers.
+ enum class Priority {
+ // The Accessibility level is the highest, and gets events before
+ // other priority levels. This allows accessibility features to
+ // modify events directly from the user.
+ kAccessibility,
+
+ // System priority EventHandlers get events before default level, and
+ // should be used for drag and drop, menus, etc.
+ kSystem,
+
+ // The default level should be used by most EventHandlers.
+ kDefault,
+ };
+
// Adds a handler to receive events before the target. The handler must be
// explicitly removed from the target before the handler is destroyed. The
// EventTarget does not take ownership of the handler.
- void AddPreTargetHandler(EventHandler* handler);
-
- // Same as AddPreTargetHandler except that the |handler| is added to the front
- // of the list so it is the first one to receive events.
- void PrependPreTargetHandler(EventHandler* handler);
+ void AddPreTargetHandler(EventHandler* handler,
+ Priority priority = Priority::kDefault);
void RemovePreTargetHandler(EventHandler* handler);
// Adds a handler to receive events after the target. The handler must be
@@ -87,6 +95,17 @@ class EVENTS_EXPORT EventTarget {
friend class EventDispatcher;
friend class EventTargetTestApi;
+ // A handler with a priority.
+ struct PrioritizedHandler {
+ EventHandler* handler = nullptr;
+ Priority priority = Priority::kDefault;
+
+ bool operator<(const PrioritizedHandler& ph) const {
+ return priority < ph.priority;
+ }
+ };
+ using EventHandlerPriorityList = std::vector<PrioritizedHandler>;
+
// Returns the list of handlers that should receive the event before the
// target. The handlers from the outermost target are first in the list, and
// the handlers on |this| are the last in the list.
@@ -97,7 +116,7 @@ class EVENTS_EXPORT EventTarget {
// the handlers on |this| are the first in the list.
void GetPostTargetHandlers(EventHandlerList* list);
- EventHandlerList pre_target_list_;
+ EventHandlerPriorityList pre_target_list_;
EventHandlerList post_target_list_;
EventHandler* target_handler_;
diff --git a/chromium/ui/events/event_target_unittest.cc b/chromium/ui/events/event_target_unittest.cc
new file mode 100644
index 00000000000..4b98d5dc905
--- /dev/null
+++ b/chromium/ui/events/event_target_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/event_target.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/events_test_utils.h"
+#include "ui/events/test/test_event_handler.h"
+#include "ui/events/test/test_event_processor.h"
+#include "ui/events/test/test_event_target.h"
+
+namespace ui {
+
+namespace {
+
+TEST(EventTargetTest, AddsAndRemovesHandlers) {
+ test::TestEventTarget target;
+ EventTargetTestApi test_api(&target);
+ test::TestEventHandler handler;
+ EventHandlerList list;
+
+ // Try at the default priority
+ target.AddPreTargetHandler(&handler);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(1u, list.size());
+ target.RemovePreTargetHandler(&handler);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(0u, list.size());
+
+ // Try at a different priority
+ target.AddPreTargetHandler(&handler, EventTarget::Priority::kAccessibility);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(1u, list.size());
+ target.RemovePreTargetHandler(&handler);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(0u, list.size());
+
+ // Doesn't crash if we remove a handler that doesn't exist.
+ target.RemovePreTargetHandler(&handler);
+}
+
+TEST(EventTargetTest, HandlerOrdering) {
+ test::TestEventTarget target;
+ EventTargetTestApi test_api(&target);
+ test::TestEventHandler default_handler;
+ test::TestEventHandler system_handler;
+ test::TestEventHandler a11y_handler;
+ EventHandlerList list;
+
+ // Try adding default then system then a11y, which is backwards of the
+ // desired order.
+ target.AddPreTargetHandler(&default_handler, EventTarget::Priority::kDefault);
+ target.AddPreTargetHandler(&system_handler, EventTarget::Priority::kSystem);
+ target.AddPreTargetHandler(&a11y_handler,
+ EventTarget::Priority::kAccessibility);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(list[0], &a11y_handler);
+ EXPECT_EQ(list[1], &system_handler);
+ EXPECT_EQ(list[2], &default_handler);
+}
+
+TEST(EventTargetTest, HandlerOrderingComplex) {
+ test::TestEventTarget target;
+ EventTargetTestApi test_api(&target);
+ test::TestEventHandler default_handler_1;
+ test::TestEventHandler default_handler_2;
+ test::TestEventHandler system_handler_1;
+ test::TestEventHandler system_handler_2;
+ test::TestEventHandler system_handler_3;
+ test::TestEventHandler a11y_handler_1;
+ test::TestEventHandler a11y_handler_2;
+ EventHandlerList list;
+
+ // Adding a new system or accessibility handler will insert it before others
+ // of its type. Adding a new default handler puts it at the end of the list,
+ // but this will change in a later patch set.
+ target.AddPreTargetHandler(&system_handler_3, EventTarget::Priority::kSystem);
+ target.AddPreTargetHandler(&default_handler_2,
+ EventTarget::Priority::kDefault);
+ target.AddPreTargetHandler(&system_handler_2, EventTarget::Priority::kSystem);
+ target.AddPreTargetHandler(&a11y_handler_2,
+ EventTarget::Priority::kAccessibility);
+ target.AddPreTargetHandler(&system_handler_1, EventTarget::Priority::kSystem);
+ target.AddPreTargetHandler(&default_handler_1,
+ EventTarget::Priority::kDefault);
+ target.AddPreTargetHandler(&a11y_handler_1,
+ EventTarget::Priority::kAccessibility);
+ list = test_api.GetPreTargetHandlers();
+ ASSERT_EQ(7u, list.size());
+ EXPECT_EQ(list[0], &a11y_handler_1);
+ EXPECT_EQ(list[1], &a11y_handler_2);
+ EXPECT_EQ(list[2], &system_handler_1);
+ EXPECT_EQ(list[3], &system_handler_2);
+ EXPECT_EQ(list[4], &system_handler_3);
+ EXPECT_EQ(list[5], &default_handler_2);
+ EXPECT_EQ(list[6], &default_handler_1);
+}
+
+} // namespace
+
+} // namespace ui
diff --git a/chromium/ui/events/event_unittest.cc b/chromium/ui/events/event_unittest.cc
index 3702b5b1daa..aba11b95f62 100644
--- a/chromium/ui/events/event_unittest.cc
+++ b/chromium/ui/events/event_unittest.cc
@@ -88,112 +88,107 @@ TEST(EventTest, ClickCount) {
TEST(EventTest, RepeatedClick) {
const gfx::Point origin(0, 0);
- MouseEvent mouse_ev1(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(), 0,
- 0);
- MouseEvent mouse_ev2(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(), 0,
- 0);
- LocatedEventTestApi test_ev1(&mouse_ev1);
- LocatedEventTestApi test_ev2(&mouse_ev2);
+ MouseEvent event1(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(), 0, 0);
+ MouseEvent event2(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(), 0, 0);
+ LocatedEventTestApi test_event1(&event1);
+ LocatedEventTestApi test_event2(&event2);
base::TimeTicks start = base::TimeTicks();
base::TimeTicks soon = start + base::TimeDelta::FromMilliseconds(1);
base::TimeTicks later = start + base::TimeDelta::FromMilliseconds(1000);
- // Same event.
- test_ev1.set_location(gfx::Point(0, 0));
- test_ev2.set_location(gfx::Point(1, 0));
- test_ev1.set_time_stamp(start);
- test_ev2.set_time_stamp(start);
- EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2));
- MouseEvent mouse_ev3(mouse_ev1);
- EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev3));
+ // Same time stamp (likely the same native event).
+ test_event1.set_location(gfx::Point(0, 0));
+ test_event2.set_location(gfx::Point(1, 0));
+ test_event1.set_time_stamp(start);
+ test_event2.set_time_stamp(start);
+ EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(event1, event2));
+ MouseEvent mouse_ev3(event1);
+ EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(event1, mouse_ev3));
// Close point.
- test_ev1.set_location(gfx::Point(0, 0));
- test_ev2.set_location(gfx::Point(1, 0));
- test_ev1.set_time_stamp(start);
- test_ev2.set_time_stamp(soon);
- EXPECT_TRUE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2));
+ test_event1.set_location(gfx::Point(0, 0));
+ test_event2.set_location(gfx::Point(1, 0));
+ test_event1.set_time_stamp(start);
+ test_event2.set_time_stamp(soon);
+ EXPECT_TRUE(MouseEvent::IsRepeatedClickEvent(event1, event2));
// Too far.
- test_ev1.set_location(gfx::Point(0, 0));
- test_ev2.set_location(gfx::Point(10, 0));
- test_ev1.set_time_stamp(start);
- test_ev2.set_time_stamp(soon);
- EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2));
+ test_event1.set_location(gfx::Point(0, 0));
+ test_event2.set_location(gfx::Point(10, 0));
+ test_event1.set_time_stamp(start);
+ test_event2.set_time_stamp(soon);
+ EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(event1, event2));
// Too long a time between clicks.
- test_ev1.set_location(gfx::Point(0, 0));
- test_ev2.set_location(gfx::Point(0, 0));
- test_ev1.set_time_stamp(start);
- test_ev2.set_time_stamp(later);
- EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2));
+ test_event1.set_location(gfx::Point(0, 0));
+ test_event2.set_location(gfx::Point(0, 0));
+ test_event1.set_time_stamp(start);
+ test_event2.set_time_stamp(later);
+ EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(event1, event2));
}
-// Tests that an event only increases the click count and gets marked as a
-// double click if a release event was seen for the previous click. This
-// prevents the same PRESSED event from being processed twice:
-// http://crbug.com/389162
-TEST(EventTest, DoubleClickRequiresRelease) {
- const gfx::Point origin1(0, 0);
- const gfx::Point origin2(100, 0);
- std::unique_ptr<MouseEvent> ev;
- base::TimeTicks start = base::TimeTicks();
- base::TimeTicks soon = start + base::TimeDelta::FromMilliseconds(1);
+// Tests that re-processing the same mouse press event (detected by timestamp)
+// does not yield a double click event: http://crbug.com/389162
+TEST(EventTest, DoubleClickRequiresUniqueTimestamp) {
+ const gfx::Point point(0, 0);
+ base::TimeTicks time1 = base::TimeTicks();
+ base::TimeTicks time2 = time1 + base::TimeDelta::FromMilliseconds(1);
+
+ // Re-processing the same press doesn't yield a double-click.
+ MouseEvent event(ET_MOUSE_PRESSED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ // Processing a press with the same timestamp doesn't yield a double-click.
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ // Processing a press with a later timestamp does yield a double-click.
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time2, 0, 0);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(event));
+ MouseEvent::ResetLastClickForTest();
+
+ // Test processing a double press and release sequence with one timestamp.
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_RELEASED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_RELEASED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ MouseEvent::ResetLastClickForTest();
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin1, origin1, EventTimeForNow(),
- 0, 0));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin1, origin1, EventTimeForNow(),
- 0, 0));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
-
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin2, origin2, EventTimeForNow(),
- 0, 0));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_RELEASED, origin2, origin2,
- EventTimeForNow(), 0, 0));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin2, origin2, EventTimeForNow(),
- 0, 0));
- ev->set_time_stamp(soon);
- EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_RELEASED, origin2, origin2,
- EventTimeForNow(), 0, 0));
- ev->set_time_stamp(soon);
- EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
+ // Test processing a double press and release sequence with two timestamps.
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_RELEASED, point, point, time1, 0, 0);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time2, 0, 0);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_RELEASED, point, point, time2, 0, 0);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(event));
MouseEvent::ResetLastClickForTest();
}
-// Tests that clicking right and then left clicking does not generate a double
-// click.
+// Tests that right clicking, then left clicking does not yield double clicks.
TEST(EventTest, SingleClickRightLeft) {
- const gfx::Point origin(0, 0);
- std::unique_ptr<MouseEvent> ev;
- base::TimeTicks start = base::TimeTicks();
- base::TimeTicks soon = start + base::TimeDelta::FromMilliseconds(1);
-
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(),
- ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_RIGHT_MOUSE_BUTTON));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_RELEASED, origin, origin, EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- ev->set_time_stamp(start);
- EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
- ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- ev->set_time_stamp(soon);
- EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
+ const gfx::Point point(0, 0);
+ base::TimeTicks time1 = base::TimeTicks();
+ base::TimeTicks time2 = time1 + base::TimeDelta::FromMilliseconds(1);
+ base::TimeTicks time3 = time1 + base::TimeDelta::FromMilliseconds(2);
+
+ MouseEvent event(ET_MOUSE_PRESSED, point, point, time1,
+ ui::EF_RIGHT_MOUSE_BUTTON, ui::EF_RIGHT_MOUSE_BUTTON);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_RELEASED, point, point, time2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(event));
+ event = MouseEvent(ET_MOUSE_PRESSED, point, point, time3,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(event));
MouseEvent::ResetLastClickForTest();
}
@@ -1166,8 +1161,8 @@ const struct AltGraphEventTestCase {
EF_ALTGR_DOWN},
};
-class AltGraphEventTest : public testing::TestWithParam<
- std::tr1::tuple<UINT, AltGraphEventTestCase>> {
+class AltGraphEventTest
+ : public testing::TestWithParam<std::tuple<UINT, AltGraphEventTestCase>> {
public:
AltGraphEventTest()
: msg_({nullptr, message_type(),
@@ -1193,9 +1188,9 @@ class AltGraphEventTest : public testing::TestWithParam<
}
protected:
- UINT message_type() const { return std::tr1::get<0>(GetParam()); }
+ UINT message_type() const { return std::get<0>(GetParam()); }
const AltGraphEventTestCase& test_case() const {
- return std::tr1::get<1>(GetParam());
+ return std::get<1>(GetParam());
}
const MSG msg_;
diff --git a/chromium/ui/events/event_utils.cc b/chromium/ui/events/event_utils.cc
index aa9b26e309d..a92ebb5a669 100644
--- a/chromium/ui/events/event_utils.cc
+++ b/chromium/ui/events/event_utils.cc
@@ -16,7 +16,7 @@ namespace {
int g_custom_event_types = ET_LAST;
} // namespace
-std::unique_ptr<Event> EventFromNative(const base::NativeEvent& native_event) {
+std::unique_ptr<Event> EventFromNative(const PlatformEvent& native_event) {
std::unique_ptr<Event> event;
EventType type = EventTypeFromNative(native_event);
switch(type) {
@@ -103,7 +103,7 @@ display::Display::TouchSupport GetInternalDisplayTouchSupport() {
return display::Display::TouchSupport::UNAVAILABLE;
}
-void ComputeEventLatencyOS(const base::NativeEvent& native_event) {
+void ComputeEventLatencyOS(const PlatformEvent& native_event) {
base::TimeTicks current_time = EventTimeForNow();
base::TimeTicks time_stamp = EventTimeFromNative(native_event);
base::TimeDelta delta = current_time - time_stamp;
diff --git a/chromium/ui/events/event_utils.h b/chromium/ui/events/event_utils.h
index 5e1d931efea..b0672fe107a 100644
--- a/chromium/ui/events/event_utils.h
+++ b/chromium/ui/events/event_utils.h
@@ -9,7 +9,6 @@
#include <memory>
-#include "base/event_types.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "ui/display/display.h"
@@ -18,6 +17,7 @@
#include "ui/events/event_constants.h"
#include "ui/events/events_export.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/native_widget_types.h"
#if defined(OS_WIN)
@@ -43,20 +43,19 @@ enum class DomCode;
// Returns a ui::Event wrapping a native event. Ownership of the returned value
// is transferred to the caller.
EVENTS_EXPORT std::unique_ptr<Event> EventFromNative(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
// Get the EventType from a native event.
-EVENTS_EXPORT EventType EventTypeFromNative(
- const base::NativeEvent& native_event);
+EVENTS_EXPORT EventType EventTypeFromNative(const PlatformEvent& native_event);
// Get the EventFlags from a native event.
-EVENTS_EXPORT int EventFlagsFromNative(const base::NativeEvent& native_event);
+EVENTS_EXPORT int EventFlagsFromNative(const PlatformEvent& native_event);
// Get the timestamp from a native event.
// Note: This is not a pure function meaning that multiple applications on the
// same native event may return different values.
EVENTS_EXPORT base::TimeTicks EventTimeFromNative(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
// Ensures that the event timestamp values are coming from the same underlying
// monotonic clock as base::TimeTicks::Now() and if it is not then falls
@@ -68,67 +67,64 @@ EVENTS_EXPORT void ValidateEventTimeClock(base::TimeTicks* timestamp);
// this "root window" and how it maps to platform-specific drawing surfaces is
// defined in ui/aura/root_window.* and ui/aura/window_tree_host*.
EVENTS_EXPORT gfx::PointF EventLocationFromNative(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
// Gets the location in native system coordinate space.
EVENTS_EXPORT gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
#if defined(USE_X11)
// Returns the 'real' button for an event. The button reported in slave events
// does not take into account any remapping (e.g. using xmodmap), while the
// button reported in master events do. This is a utility function to always
// return the mapped button.
-EVENTS_EXPORT int EventButtonFromNative(const base::NativeEvent& native_event);
+EVENTS_EXPORT int EventButtonFromNative(const PlatformEvent& native_event);
#endif
// Returns the KeyboardCode from a native event.
-EVENTS_EXPORT KeyboardCode KeyboardCodeFromNative(
- const base::NativeEvent& native_event);
+EVENTS_EXPORT KeyboardCode
+KeyboardCodeFromNative(const PlatformEvent& native_event);
// Returns the DOM KeyboardEvent code (physical location in the
// keyboard) from a native event.
-EVENTS_EXPORT DomCode CodeFromNative(const base::NativeEvent& native_event);
+EVENTS_EXPORT DomCode CodeFromNative(const PlatformEvent& native_event);
// Returns true if the keyboard event is a character event rather than
// a keystroke event.
-EVENTS_EXPORT bool IsCharFromNative(const base::NativeEvent& native_event);
+EVENTS_EXPORT bool IsCharFromNative(const PlatformEvent& native_event);
// Returns the flags of the button that changed during a press/release.
EVENTS_EXPORT int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
// Returns the detailed pointer information for mouse events.
-EVENTS_EXPORT PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event);
+EVENTS_EXPORT PointerDetails
+GetMousePointerDetailsFromNative(const PlatformEvent& native_event);
// Gets the mouse wheel offsets from a native event.
EVENTS_EXPORT gfx::Vector2d GetMouseWheelOffset(
- const base::NativeEvent& native_event);
+ const PlatformEvent& native_event);
// Returns a copy of |native_event|. Depending on the platform, this copy may
// need to be deleted with ReleaseCopiedNativeEvent().
-base::NativeEvent CopyNativeEvent(
- const base::NativeEvent& native_event);
+PlatformEvent CopyNativeEvent(const PlatformEvent& native_event);
// Delete a |native_event| previously created by CopyNativeEvent().
-void ReleaseCopiedNativeEvent(
- const base::NativeEvent& native_event);
+void ReleaseCopiedNativeEvent(const PlatformEvent& native_event);
// Returns the detailed pointer information for touch events.
EVENTS_EXPORT PointerDetails
-GetTouchPointerDetailsFromNative(const base::NativeEvent& native_event);
+GetTouchPointerDetailsFromNative(const PlatformEvent& native_event);
// Gets the touch id from a native event.
-EVENTS_EXPORT int GetTouchId(const base::NativeEvent& native_event);
+EVENTS_EXPORT int GetTouchId(const PlatformEvent& native_event);
// Clear the touch id from bookkeeping if it is a release/cancel event.
-EVENTS_EXPORT void ClearTouchIdIfReleased(
- const base::NativeEvent& native_event);
+EVENTS_EXPORT void ClearTouchIdIfReleased(const PlatformEvent& native_event);
// Gets the fling velocity from a native event. is_cancel is set to true if
// this was a tap down, intended to stop an ongoing fling.
-EVENTS_EXPORT bool GetFlingData(const base::NativeEvent& native_event,
+EVENTS_EXPORT bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
@@ -137,7 +133,7 @@ EVENTS_EXPORT bool GetFlingData(const base::NativeEvent& native_event,
// Returns whether this is a scroll event and optionally gets the amount to be
// scrolled. |x_offset|, |y_offset| and |finger_count| can be NULL.
-EVENTS_EXPORT bool GetScrollOffsets(const base::NativeEvent& native_event,
+EVENTS_EXPORT bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -151,7 +147,7 @@ EVENTS_EXPORT bool ShouldDefaultToNaturalScroll();
// Returns whether or not the internal display produces touch events.
EVENTS_EXPORT display::Display::TouchSupport GetInternalDisplayTouchSupport();
-EVENTS_EXPORT void ComputeEventLatencyOS(const base::NativeEvent& native_event);
+EVENTS_EXPORT void ComputeEventLatencyOS(const PlatformEvent& native_event);
#if defined(OS_WIN)
EVENTS_EXPORT int GetModifiersFromKeyState();
diff --git a/chromium/ui/events/events_default.cc b/chromium/ui/events/events_default.cc
index 665e21d67d4..f293ed60bd1 100644
--- a/chromium/ui/events/events_default.cc
+++ b/chromium/ui/events/events_default.cc
@@ -8,23 +8,22 @@
namespace ui {
-base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->time_stamp();
}
-int EventFlagsFromNative(const base::NativeEvent& native_event) {
+int EventFlagsFromNative(const PlatformEvent& native_event) {
const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->flags();
}
-EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
const ui::Event* event = static_cast<const ui::Event*>(native_event);
return event->type();
}
-gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event) {
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
const ui::LocatedEvent* e =
static_cast<const ui::LocatedEvent*>(native_event);
DCHECK(e->IsMouseEvent() || e->IsTouchEvent() || e->IsGestureEvent() ||
@@ -32,7 +31,7 @@ gfx::Point EventSystemLocationFromNative(
return e->location();
}
-gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
const ui::LocatedEvent* e =
static_cast<const ui::LocatedEvent*>(native_event);
DCHECK(e->IsMouseEvent() || e->IsTouchEvent() || e->IsGestureEvent() ||
@@ -40,8 +39,7 @@ gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
return e->location_f();
}
-int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event) {
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
const ui::MouseEvent* event =
static_cast<const ui::MouseEvent*>(native_event);
DCHECK(event->IsMouseEvent() || event->IsScrollEvent());
@@ -49,7 +47,7 @@ int GetChangedMouseButtonFlagsFromNative(
}
PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
const ui::MouseEvent* event =
static_cast<const ui::MouseEvent*>(native_event);
DCHECK(event->IsMouseEvent() || event->IsScrollEvent());
@@ -58,43 +56,41 @@ PointerDetails GetMousePointerDetailsFromNative(
return pointer_detail;
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
DCHECK(event->IsKeyEvent());
return event->key_code();
}
-DomCode CodeFromNative(const base::NativeEvent& native_event) {
+DomCode CodeFromNative(const PlatformEvent& native_event) {
const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
DCHECK(event->IsKeyEvent());
return event->code();
}
-bool IsCharFromNative(const base::NativeEvent& native_event) {
+bool IsCharFromNative(const PlatformEvent& native_event) {
const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
DCHECK(event->IsKeyEvent());
return event->is_char();
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& native_event) {
const ui::MouseWheelEvent* event =
static_cast<const ui::MouseWheelEvent*>(native_event);
DCHECK(event->type() == ET_MOUSEWHEEL);
return event->offset();
}
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+PlatformEvent CopyNativeEvent(const PlatformEvent& event) {
return NULL;
}
-void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
-}
+void ReleaseCopiedNativeEvent(const PlatformEvent& event) {}
-void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
-}
+void ClearTouchIdIfReleased(const PlatformEvent& xev) {}
// TODO(687724): Will remove all GetTouchId functions.
-int GetTouchId(const base::NativeEvent& native_event) {
+int GetTouchId(const PlatformEvent& native_event) {
const ui::TouchEvent* event =
static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
@@ -102,14 +98,14 @@ int GetTouchId(const base::NativeEvent& native_event) {
}
PointerDetails GetTouchPointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
const ui::TouchEvent* event =
static_cast<const ui::TouchEvent*>(native_event);
DCHECK(event->IsTouchEvent());
return event->pointer_details();
}
-bool GetScrollOffsets(const base::NativeEvent& native_event,
+bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -135,7 +131,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
return true;
}
-bool GetFlingData(const base::NativeEvent& native_event,
+bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
diff --git a/chromium/ui/events/events_stub.cc b/chromium/ui/events/events_stub.cc
index 26fc632d9d2..b9529520cb9 100644
--- a/chromium/ui/events/events_stub.cc
+++ b/chromium/ui/events/events_stub.cc
@@ -17,73 +17,69 @@ namespace ui {
// Stub implementations of platform-specific methods in events_util.h, built
// on platforms that currently do not have a complete implementation of events.
-EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return ET_UNKNOWN;
}
-int EventFlagsFromNative(const base::NativeEvent& native_event) {
+int EventFlagsFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
-base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return base::TimeTicks();
}
-gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return gfx::PointF();
}
-gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event) {
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return gfx::Point();
}
-int EventButtonFromNative(const base::NativeEvent& native_event) {
+int EventButtonFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
-int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event) {
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
return PointerDetails(EventPointerType::POINTER_TYPE_MOUSE);
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return gfx::Vector2d();
}
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
- NOTIMPLEMENTED() <<
- "Don't know how to copy base::NativeEvent for this platform";
+PlatformEvent CopyNativeEvent(const PlatformEvent& event) {
+ NOTIMPLEMENTED() << "Don't know how to copy PlatformEvent for this platform";
return NULL;
}
-void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
-}
+void ReleaseCopiedNativeEvent(const PlatformEvent& event) {}
-void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
+void ClearTouchIdIfReleased(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
}
-int GetTouchId(const base::NativeEvent& native_event) {
+int GetTouchId(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
PointerDetails GetTouchPointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return PointerDetails(EventPointerType::POINTER_TYPE_UNKNOWN,
/* radius_x */ 1.0,
@@ -94,7 +90,7 @@ PointerDetails GetTouchPointerDetailsFromNative(
/* tilt_y */ 0.f);
}
-bool GetScrollOffsets(const base::NativeEvent& native_event,
+bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -105,7 +101,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
return false;
}
-bool GetFlingData(const base::NativeEvent& native_event,
+bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
@@ -115,32 +111,32 @@ bool GetFlingData(const base::NativeEvent& native_event,
return false;
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return static_cast<KeyboardCode>(0);
}
-DomCode CodeFromNative(const base::NativeEvent& native_event) {
+DomCode CodeFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return DomCode::NONE;
}
-bool IsCharFromNative(const base::NativeEvent& native_event) {
+bool IsCharFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return false;
}
-uint32_t WindowsKeycodeFromNative(const base::NativeEvent& native_event) {
+uint32_t WindowsKeycodeFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
-uint16_t TextFromNative(const base::NativeEvent& native_event) {
+uint16_t TextFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
-uint16_t UnmodifiedTextFromNative(const base::NativeEvent& native_event) {
+uint16_t UnmodifiedTextFromNative(const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return 0;
}
diff --git a/chromium/ui/events/gestures/blink/BUILD.gn b/chromium/ui/events/gestures/blink/BUILD.gn
index e52f4a462ca..5ba80ccac1a 100644
--- a/chromium/ui/events/gestures/blink/BUILD.gn
+++ b/chromium/ui/events/gestures/blink/BUILD.gn
@@ -10,7 +10,7 @@ source_set("blink") {
deps = [
"//base",
- "//third_party/WebKit/public:blink_headers",
+ "//third_party/blink/public:blink_headers",
"//ui/events",
"//ui/events:gesture_detection",
"//ui/gfx/geometry",
diff --git a/chromium/ui/events/gestures/blink/DEPS b/chromium/ui/events/gestures/blink/DEPS
index 8d8323e9688..61b00b07eac 100644
--- a/chromium/ui/events/gestures/blink/DEPS
+++ b/chromium/ui/events/gestures/blink/DEPS
@@ -1,6 +1,6 @@
include_rules = [
- "+third_party/WebKit/public/platform/WebFloatSize.h",
- "+third_party/WebKit/public/platform/WebGestureCurve.h",
- "+third_party/WebKit/public/platform/WebGestureDevice.h",
- "+third_party/WebKit/public/platform/WebGestureCurveTarget.h"
+ "+third_party/blink/public/platform/web_float_size.h",
+ "+third_party/blink/public/platform/web_gesture_curve.h",
+ "+third_party/blink/public/platform/web_gesture_device.h",
+ "+third_party/blink/public/platform/web_gesture_curve_target.h"
]
diff --git a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc
index b2aec0cbeb1..cc8d67ea2e3 100644
--- a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc
+++ b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc
@@ -9,11 +9,10 @@
#include <utility>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h"
+#include "third_party/blink/public/platform/web_float_size.h"
+#include "third_party/blink/public/platform/web_gesture_curve_target.h"
#include "ui/events/gestures/fixed_velocity_curve.h"
#include "ui/events/gestures/fling_curve.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
diff --git a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.h b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.h
index 4480fdcfa43..ede9a036d52 100644
--- a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.h
+++ b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.h
@@ -11,8 +11,8 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "third_party/WebKit/public/platform/WebGestureDevice.h"
+#include "third_party/blink/public/platform/web_gesture_curve.h"
+#include "third_party/blink/public/platform/web_gesture_device.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace ui {
diff --git a/chromium/ui/events/gestures/blink/web_gesture_curve_impl_unittest.cc b/chromium/ui/events/gestures/blink/web_gesture_curve_impl_unittest.cc
index c5c6cfa6e8f..63b56a427d9 100644
--- a/chromium/ui/events/gestures/blink/web_gesture_curve_impl_unittest.cc
+++ b/chromium/ui/events/gestures/blink/web_gesture_curve_impl_unittest.cc
@@ -7,9 +7,9 @@
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "third_party/WebKit/public/platform/WebGestureCurve.h"
-#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h"
+#include "third_party/blink/public/platform/web_float_size.h"
+#include "third_party/blink/public/platform/web_gesture_curve.h"
+#include "third_party/blink/public/platform/web_gesture_curve_target.h"
#include "ui/events/gestures/fling_curve.h"
using blink::WebFloatSize;
diff --git a/chromium/ui/events/keyboard_hook.h b/chromium/ui/events/keyboard_hook.h
index 32f05492772..ea99e978353 100644
--- a/chromium/ui/events/keyboard_hook.h
+++ b/chromium/ui/events/keyboard_hook.h
@@ -33,6 +33,9 @@ class EVENTS_EXPORT KeyboardHook {
static std::unique_ptr<KeyboardHook> Create(
base::Optional<base::flat_set<int>> native_key_codes,
KeyEventCallback callback);
+
+ // True if |native_key_code| is reserved for an active KeyboardLock request.
+ virtual bool IsKeyLocked(int native_key_code) = 0;
};
} // namespace ui
diff --git a/chromium/ui/events/keyboard_hook_base.cc b/chromium/ui/events/keyboard_hook_base.cc
index d9a7938ff30..ae0e785a7bf 100644
--- a/chromium/ui/events/keyboard_hook_base.cc
+++ b/chromium/ui/events/keyboard_hook_base.cc
@@ -22,6 +22,10 @@ KeyboardHookBase::KeyboardHookBase(
KeyboardHookBase::~KeyboardHookBase() = default;
+bool KeyboardHookBase::IsKeyLocked(int native_key_code) {
+ return ShouldCaptureKeyEvent(native_key_code);
+}
+
bool KeyboardHookBase::ShouldCaptureKeyEvent(int key_code) const {
return !key_codes_ || base::ContainsKey(key_codes_.value(), key_code);
}
diff --git a/chromium/ui/events/keyboard_hook_base.h b/chromium/ui/events/keyboard_hook_base.h
index 428c24fa077..c0aa26ab155 100644
--- a/chromium/ui/events/keyboard_hook_base.h
+++ b/chromium/ui/events/keyboard_hook_base.h
@@ -20,6 +20,9 @@ class KeyboardHookBase : public KeyboardHook {
KeyEventCallback callback);
~KeyboardHookBase() override;
+ // KeyboardHook implementation.
+ bool IsKeyLocked(int native_key_code) override;
+
protected:
// Indicates whether |key_code| should be intercepted by the keyboard hook.
bool ShouldCaptureKeyEvent(int key_code) const;
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
index ce35f7508dc..34c5ff80e1b 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
@@ -25,9 +25,83 @@ namespace ui {
namespace {
// MAP0 - MAP3:
-// These are the generated VKEY code maps for all possible Latin keyboard
-// layouts in Windows. And the maps are only for special letter keys excluding
-// [a-z] & [0-9].
+// These are the generated VKEY code maps from these layout datas on Windows:
+// KBDA1.DLL
+// KBDAL.DLL
+// KBDARME.DLL
+// KBDARMW.DLL
+// KBDAZEL.DLL
+// KBDBE.DLL
+// KBDBENE.DLL
+// KBDBR.DLL
+// KBDCA.DLL
+// KBDCAN.DLL
+// KBDCR.DLL
+// KBDCZ.DLL
+// KBDCZ1.DLL
+// KBDCZ2.DLL
+// KBDDA.DLL
+// KBDDV.DLL
+// KBDES.DLL
+// KBDEST.DLL
+// KBDFC.DLL
+// KBDFI.DLL
+// KBDFI1.DLL
+// KBDFO.DLL
+// KBDFR.DLL
+// KBDHEB.DLL
+// KBDGAE.DLL
+// KBDGEO.DLL
+// kbdgeoer.dll
+// kbdgeoqw.dll
+// KBDGR.DLL
+// KBDGR1.DLL
+// KBDGRLND.DLL
+// KBDHAU.DLL
+// KBDHU.DLL
+// KBDHU1.DLL
+// KBDIBO.DLL
+// KBDIC.DLL
+// KBDIR.DLL
+// KBDIT.DLL
+// KBDIT142.DLL
+// KBDLA.DLL
+// KBDLT.DLL
+// KBDLT1.DLL
+// KBDLT2.DLL
+// KBDLV.DLL
+// KBDLV1.DLL
+// KBDMLT47.DLL
+// KBDMLT48.DLL
+// KBDNE.DLL
+// KBDNO.DLL
+// KBDNO1.DLL
+// KBDPL.DLL
+// KBDPL1.DLL
+// KBDPO.DLL
+// KBDRO.DLL
+// KBDROPR.DLL
+// KBDROST.DLL
+// KBDRU.DLL
+// KBDSF.DLL
+// KBDSG.DLL
+// KBDSL.DLL
+// KBDSL1.DLL
+// KBDSOREX.DLL
+// KBDSORS1.DLL
+// KBDSORST.DLL
+// KBDSP.DLL
+// KBDSW.DLL
+// KBDSW09.DLL
+// KBDUK.DLL
+// KBDUKX.DLL
+// KBDUS.DLL
+// KBDUSL.DLL
+// KBDUSR.DLL
+// KBDUSX.DLL
+// KBDVNTC.DLL
+// KBDYBA.DLL
+// And the maps are only for special letter keys excluding [a-z] & [0-9].
//
// ch0: the keysym without modifier states.
// ch1: the keysym with shift state.
@@ -122,179 +196,183 @@ const struct MAP1 {
return m1.ch0 < m2.ch0;
}
} map1[] = {
- {0x0021, 0x0A, 0x31}, // XK_exclam+AE01: VKEY_1
- {0x0021, 0x11, 0x38}, // XK_exclam+AE08: VKEY_8
- {0x0021, 0x3D, 0xDF}, // XK_exclam+AB10: VKEY_OEM_8
- {0x0022, 0x0B, 0x32}, // XK_quotedbl+AE02: VKEY_2
- {0x0022, 0x0C, 0x33}, // XK_quotedbl+AE03: VKEY_3
- {0x0023, 0x31, 0xDE}, // XK_numbersign+TLDE: VKEY_OEM_7
- {0x0024, 0x23, 0xBA}, // XK_dollar+AD12: VKEY_OEM_1
- {0x0024, 0x33, 0xDF}, // XK_dollar+BKSL: VKEY_OEM_8
- {0x0027, 0x0D, 0x34}, // XK_quoteright+AE04: VKEY_4
- {0x0027, 0x18, 0xDE}, // XK_quoteright+AD01: VKEY_OEM_7
- {0x0027, 0x23, 0xBA}, // XK_quoteright+AD12: VKEY_OEM_1
- {0x0027, 0x3D, 0xDE}, // XK_quoteright+AB10: VKEY_OEM_7
- {0x0028, 0x0E, 0x35}, // XK_parenleft+AE05: VKEY_5
- {0x0028, 0x12, 0x39}, // XK_parenleft+AE09: VKEY_9
- {0x0028, 0x33, 0xDC}, // XK_parenleft+BKSL: VKEY_OEM_5
- {0x0029, 0x13, 0x30}, // XK_parenright+AE10: VKEY_0
- {0x0029, 0x14, 0xDB}, // XK_parenright+AE11: VKEY_OEM_4
- {0x0029, 0x23, 0xDD}, // XK_parenright+AD12: VKEY_OEM_6
- {0x002A, 0x23, 0xBA}, // XK_asterisk+AD12: VKEY_OEM_1
- {0x002A, 0x33, 0xDC}, // XK_asterisk+BKSL: VKEY_OEM_5
- {0x002B, 0x0A, 0x31}, // XK_plus+AE01: VKEY_1
- {0x002B, 0x15, 0xBB}, // XK_plus+AE12: VKEY_OEM_PLUS
- {0x002B, 0x22, 0xBB}, // XK_plus+AD11: VKEY_OEM_PLUS
- {0x002B, 0x23, 0xBB}, // XK_plus+AD12: VKEY_OEM_PLUS
- {0x002B, 0x2F, 0xBB}, // XK_plus+AC10: VKEY_OEM_PLUS
- {0x002B, 0x33, 0xBF}, // XK_plus+BKSL: VKEY_OEM_2
- {0x002C, 0x0C, 0x33}, // XK_comma+AE03: VKEY_3
- {0x002C, 0x0E, 0x35}, // XK_comma+AE05: VKEY_5
- {0x002C, 0x0F, 0x36}, // XK_comma+AE06: VKEY_6
- {0x002C, 0x12, 0x39}, // XK_comma+AE09: VKEY_9
- {0x002C, 0x19, 0xBC}, // XK_comma+AD02: VKEY_OEM_COMMA
- {0x002C, 0x37, 0xBC}, // XK_comma+AB04: VKEY_OEM_COMMA
- {0x002C, 0x3A, 0xBC}, // XK_comma+AB07: VKEY_OEM_COMMA
- {0x002C, 0x3B, 0xBC}, // XK_comma+AB08: VKEY_OEM_COMMA
- {0x002D, 0x0B, 0x32}, // XK_minus+AE02: VKEY_2
- {0x002D, 0x0F, 0x36}, // XK_minus+AE06: VKEY_6
- {0x002D, 0x14, 0xBD}, // XK_minus+AE11: VKEY_OEM_MINUS
- {0x002D, 0x26, 0xBD}, // XK_minus+AC01: VKEY_OEM_MINUS
- {0x002D, 0x30, 0xBD}, // XK_minus+AC11: VKEY_OEM_MINUS
- {0x002E, 0x10, 0x37}, // XK_period+AE07: VKEY_7
- {0x002E, 0x11, 0x38}, // XK_period+AE08: VKEY_8
- {0x002E, 0x1A, 0xBE}, // XK_period+AD03: VKEY_OEM_PERIOD
- {0x002E, 0x1B, 0xBE}, // XK_period+AD04: VKEY_OEM_PERIOD
- {0x002E, 0x20, 0xBE}, // XK_period+AD09: VKEY_OEM_PERIOD
- {0x002E, 0x30, 0xDE}, // XK_period+AC11: VKEY_OEM_7
- {0x002E, 0x3C, 0xBE}, // XK_period+AB09: VKEY_OEM_PERIOD
- {0x002E, 0x3D, 0xBF}, // XK_period+AB10: VKEY_OEM_2
- {0x002F, 0x14, 0xDB}, // XK_slash+AE11: VKEY_OEM_4
- {0x002F, 0x22, 0xBF}, // XK_slash+AD11: VKEY_OEM_2
- {0x002F, 0x31, 0xDE}, // XK_slash+TLDE: VKEY_OEM_7
- {0x002F, 0x33, 0xDC}, // XK_slash+BKSL: VKEY_OEM_5
- {0x002F, 0x3D, 0xBF}, // XK_slash+AB10: VKEY_OEM_2
- {0x003A, 0x0A, 0x31}, // XK_colon+AE01: VKEY_1
- {0x003A, 0x0E, 0x35}, // XK_colon+AE05: VKEY_5
- {0x003A, 0x0F, 0x36}, // XK_colon+AE06: VKEY_6
- {0x003A, 0x3C, 0xBF}, // XK_colon+AB09: VKEY_OEM_2
- {0x003B, 0x0D, 0x34}, // XK_semicolon+AE04: VKEY_4
- {0x003B, 0x11, 0x38}, // XK_semicolon+AE08: VKEY_8
- {0x003B, 0x18, 0xBA}, // XK_semicolon+AD01: VKEY_OEM_1
- {0x003B, 0x22, 0xBA}, // XK_semicolon+AD11: VKEY_OEM_1
- {0x003B, 0x23, 0xDD}, // XK_semicolon+AD12: VKEY_OEM_6
- {0x003B, 0x2F, 0xBA}, // XK_semicolon+AC10: VKEY_OEM_1
- {0x003B, 0x31, 0xC0}, // XK_semicolon+TLDE: VKEY_OEM_3
- {0x003B, 0x34, 0xBA}, // XK_semicolon+AB01: VKEY_OEM_1
- {0x003B, 0x3B, 0xBE}, // XK_semicolon+AB08: VKEY_OEM_PERIOD
- {0x003B, 0x3D, 0xBF}, // XK_semicolon+AB10: VKEY_OEM_2
- {0x003D, 0x11, 0x38}, // XK_equal+AE08: VKEY_8
- {0x003D, 0x15, 0xBB}, // XK_equal+AE12: VKEY_OEM_PLUS
- {0x003D, 0x23, 0xBB}, // XK_equal+AD12: VKEY_OEM_PLUS
- {0x003F, 0x0B, 0x32}, // XK_question+AE02: VKEY_2
- {0x003F, 0x10, 0x37}, // XK_question+AE07: VKEY_7
- {0x003F, 0x11, 0x38}, // XK_question+AE08: VKEY_8
- {0x003F, 0x14, 0xBB}, // XK_question+AE11: VKEY_OEM_PLUS
- {0x0040, 0x23, 0xDD}, // XK_at+AD12: VKEY_OEM_6
- {0x0040, 0x31, 0xDE}, // XK_at+TLDE: VKEY_OEM_7
- {0x005B, 0x0A, 0xDB}, // XK_bracketleft+AE01: VKEY_OEM_4
- {0x005B, 0x14, 0xDB}, // XK_bracketleft+AE11: VKEY_OEM_4
- {0x005B, 0x22, 0xDB}, // XK_bracketleft+AD11: VKEY_OEM_4
- {0x005B, 0x23, 0xDD}, // XK_bracketleft+AD12: VKEY_OEM_6
- {0x005B, 0x30, 0xDE}, // XK_bracketleft+AC11: VKEY_OEM_7
- {0x005C, 0x15, 0xDB}, // XK_backslash+AE12: VKEY_OEM_4
- {0x005D, 0x0B, 0xDD}, // XK_bracketright+AE02: VKEY_OEM_6
- {0x005D, 0x15, 0xDD}, // XK_bracketright+AE12: VKEY_OEM_6
- {0x005D, 0x23, 0xDD}, // XK_bracketright+AD12: VKEY_OEM_6
- {0x005D, 0x31, 0xC0}, // XK_bracketright+TLDE: VKEY_OEM_3
- {0x005D, 0x33, 0xDC}, // XK_bracketright+BKSL: VKEY_OEM_5
- {0x005F, 0x11, 0x38}, // XK_underscore+AE08: VKEY_8
- {0x005F, 0x14, 0xBD}, // XK_underscore+AE11: VKEY_OEM_MINUS
- {0x00A7, 0x0D, 0x34}, // XK_section+AE04: VKEY_4
- {0x00A7, 0x0F, 0x36}, // XK_section+AE06: VKEY_6
- {0x00A7, 0x30, 0xDE}, // XK_section+AC11: VKEY_OEM_7
- {0x00AB, 0x11, 0x38}, // XK_guillemotleft+AE08: VKEY_8
- {0x00AB, 0x15, 0xDD}, // XK_guillemotleft+AE12: VKEY_OEM_6
- {0x00B0, 0x15, 0xBF}, // XK_degree+AE12: VKEY_OEM_2
- {0x00B0, 0x31, 0xDE}, // XK_degree+TLDE: VKEY_OEM_7
- {0x00BA, 0x30, 0xDE}, // XK_masculine+AC11: VKEY_OEM_7
- {0x00BA, 0x31, 0xDC}, // XK_masculine+TLDE: VKEY_OEM_5
- {0x00E0, 0x13, 0x30}, // XK_agrave+AE10: VKEY_0
- {0x00E0, 0x33, 0xDC}, // XK_agrave+BKSL: VKEY_OEM_5
- {0x00E1, 0x11, 0x38}, // XK_aacute+AE08: VKEY_8
- {0x00E1, 0x30, 0xDE}, // XK_aacute+AC11: VKEY_OEM_7
- {0x00E2, 0x0B, 0x32}, // XK_acircumflex+AE02: VKEY_2
- {0x00E2, 0x33, 0xDC}, // XK_acircumflex+BKSL: VKEY_OEM_5
- {0x00E4, 0x23, 0xDD}, // XK_adiaeresis+AD12: VKEY_OEM_6
- {0x00E6, 0x2F, 0xC0}, // XK_ae+AC10: VKEY_OEM_3
- {0x00E6, 0x30, 0xDE}, // XK_ae+AC11: VKEY_OEM_7
- {0x00E7, 0x12, 0x39}, // XK_ccedilla+AE09: VKEY_9
- {0x00E7, 0x22, 0xDB}, // XK_ccedilla+AD11: VKEY_OEM_4
- {0x00E7, 0x23, 0xDD}, // XK_ccedilla+AD12: VKEY_OEM_6
- {0x00E7, 0x30, 0xDE}, // XK_ccedilla+AC11: VKEY_OEM_7
- {0x00E7, 0x33, 0xBF}, // XK_ccedilla+BKSL: VKEY_OEM_2
- {0x00E7, 0x3B, 0xBC}, // XK_ccedilla+AB08: VKEY_OEM_COMMA
- {0x00E8, 0x10, 0x37}, // XK_egrave+AE07: VKEY_7
- {0x00E8, 0x22, 0xBA}, // XK_egrave+AD11: VKEY_OEM_1
- {0x00E8, 0x30, 0xC0}, // XK_egrave+AC11: VKEY_OEM_3
- {0x00E9, 0x0B, 0x32}, // XK_eacute+AE02: VKEY_2
- {0x00E9, 0x13, 0x30}, // XK_eacute+AE10: VKEY_0
- {0x00E9, 0x3D, 0xBF}, // XK_eacute+AB10: VKEY_OEM_2
- {0x00ED, 0x12, 0x39}, // XK_iacute+AE09: VKEY_9
- {0x00ED, 0x31, 0x30}, // XK_iacute+TLDE: VKEY_0
- {0x00F0, 0x22, 0xDD}, // XK_eth+AD11: VKEY_OEM_6
- {0x00F0, 0x23, 0xBA}, // XK_eth+AD12: VKEY_OEM_1
- {0x00F3, 0x15, 0xBB}, // XK_oacute+AE12: VKEY_OEM_PLUS
- {0x00F3, 0x33, 0xDC}, // XK_oacute+BKSL: VKEY_OEM_5
- {0x00F4, 0x0D, 0x34}, // XK_ocircumflex+AE04: VKEY_4
- {0x00F4, 0x2F, 0xBA}, // XK_ocircumflex+AC10: VKEY_OEM_1
- {0x00F6, 0x13, 0xC0}, // XK_odiaeresis+AE10: VKEY_OEM_3
- {0x00F6, 0x14, 0xBB}, // XK_odiaeresis+AE11: VKEY_OEM_PLUS
- {0x00F6, 0x22, 0xDB}, // XK_odiaeresis+AD11: VKEY_OEM_4
- {0x00F8, 0x2F, 0xC0}, // XK_oslash+AC10: VKEY_OEM_3
- {0x00F8, 0x30, 0xDE}, // XK_oslash+AC11: VKEY_OEM_7
- {0x00F9, 0x30, 0xC0}, // XK_ugrave+AC11: VKEY_OEM_3
- {0x00F9, 0x33, 0xBF}, // XK_ugrave+BKSL: VKEY_OEM_2
- {0x00FA, 0x22, 0xDB}, // XK_uacute+AD11: VKEY_OEM_4
- {0x00FA, 0x23, 0xDD}, // XK_uacute+AD12: VKEY_OEM_6
- {0x00FC, 0x19, 0x57}, // XK_udiaeresis+AD02: VKEY_W
- {0x01B1, 0x0A, 0x31}, // XK_aogonek+AE01: VKEY_1
- {0x01B1, 0x18, 0x51}, // XK_aogonek+AD01: VKEY_Q
- {0x01B1, 0x30, 0xDE}, // XK_aogonek+AC11: VKEY_OEM_7
- {0x01B3, 0x2F, 0xBA}, // XK_lstroke+AC10: VKEY_OEM_1
- {0x01B3, 0x33, 0xBF}, // XK_lstroke+BKSL: VKEY_OEM_2
- {0x01B9, 0x0C, 0x33}, // XK_scaron+AE03: VKEY_3
- {0x01B9, 0x0F, 0x36}, // XK_scaron+AE06: VKEY_6
- {0x01B9, 0x22, 0xDB}, // XK_scaron+AD11: VKEY_OEM_4
- {0x01B9, 0x26, 0xBA}, // XK_scaron+AC01: VKEY_OEM_1
- {0x01B9, 0x29, 0x46}, // XK_scaron+AC04: VKEY_F
- {0x01B9, 0x3C, 0xBE}, // XK_scaron+AB09: VKEY_OEM_PERIOD
- {0x01BA, 0x2F, 0xBA}, // XK_scedilla+AC10: VKEY_OEM_1
- {0x01BA, 0x3C, 0xBE}, // XK_scedilla+AB09: VKEY_OEM_PERIOD
- {0x01BE, 0x0F, 0x36}, // XK_zcaron+AE06: VKEY_6
- {0x01BE, 0x15, 0xBB}, // XK_zcaron+AE12: VKEY_OEM_PLUS
- {0x01BE, 0x19, 0x57}, // XK_zcaron+AD02: VKEY_W
- {0x01BE, 0x22, 0x59}, // XK_zcaron+AD11: VKEY_Y
- {0x01BE, 0x33, 0xDC}, // XK_zcaron+BKSL: VKEY_OEM_5
- {0x01BF, 0x22, 0xDB}, // XK_zabovedot+AD11: VKEY_OEM_4
- {0x01BF, 0x33, 0xDC}, // XK_zabovedot+BKSL: VKEY_OEM_5
- {0x01E3, 0x0A, 0x31}, // XK_abreve+AE01: VKEY_1
- {0x01E3, 0x22, 0xDB}, // XK_abreve+AD11: VKEY_OEM_4
- {0x01E8, 0x0B, 0x32}, // XK_ccaron+AE02: VKEY_2
- {0x01E8, 0x0D, 0x34}, // XK_ccaron+AE04: VKEY_4
- {0x01E8, 0x21, 0x58}, // XK_ccaron+AD10: VKEY_X
- {0x01E8, 0x2F, 0xBA}, // XK_ccaron+AC10: VKEY_OEM_1
- {0x01E8, 0x3B, 0xBC}, // XK_ccaron+AB08: VKEY_OEM_COMMA
- {0x01EA, 0x0C, 0x33}, // XK_eogonek+AE03: VKEY_3
- {0x01F0, 0x13, 0x30}, // XK_dstroke+AE10: VKEY_0
- {0x01F0, 0x23, 0xDD}, // XK_dstroke+AD12: VKEY_OEM_6
- {0x03E7, 0x0E, 0x35}, // XK_iogonek+AE05: VKEY_5
- {0x03EC, 0x0D, 0x34}, // XK_eabovedot+AE04: VKEY_4
- {0x03EC, 0x30, 0xDE}, // XK_eabovedot+AC11: VKEY_OEM_7
- {0x03F9, 0x10, 0x37}, // XK_uogonek+AE07: VKEY_7
- {0x03FE, 0x11, 0x38}, // XK_umacron+AE08: VKEY_8
- {0x03FE, 0x18, 0x51}, // XK_umacron+AD01: VKEY_Q
- {0x03FE, 0x35, 0x58}, // XK_umacron+AB02: VKEY_X
+ {0x0021, 0x0A, 0x31}, // XK_exclam+AE01: VKEY_1
+ {0x0021, 0x11, 0x38}, // XK_exclam+AE08: VKEY_8
+ {0x0021, 0x3D, 0xDF}, // XK_exclam+AB10: VKEY_OEM_8
+ {0x0022, 0x0B, 0x32}, // XK_quotedbl+AE02: VKEY_2
+ {0x0022, 0x0C, 0x33}, // XK_quotedbl+AE03: VKEY_3
+ {0x0023, 0x31, 0xDE}, // XK_numbersign+TLDE: VKEY_OEM_7
+ {0x0024, 0x23, 0xBA}, // XK_dollar+AD12: VKEY_OEM_1
+ {0x0024, 0x33, 0xDF}, // XK_dollar+BKSL: VKEY_OEM_8
+ {0x0027, 0x0D, 0x34}, // XK_quoteright+AE04: VKEY_4
+ {0x0027, 0x18, 0xDE}, // XK_quoteright+AD01: VKEY_OEM_7
+ {0x0027, 0x19, 0x57}, // XK_quoteright+AD02: VKEY_W
+ {0x0027, 0x23, 0xBA}, // XK_quoteright+AD12: VKEY_OEM_1
+ {0x0027, 0x3D, 0xDE}, // XK_quoteright+AB10: VKEY_OEM_7
+ {0x0028, 0x0E, 0x35}, // XK_parenleft+AE05: VKEY_5
+ {0x0028, 0x12, 0x39}, // XK_parenleft+AE09: VKEY_9
+ {0x0028, 0x33, 0xDC}, // XK_parenleft+BKSL: VKEY_OEM_5
+ {0x0029, 0x13, 0x30}, // XK_parenright+AE10: VKEY_0
+ {0x0029, 0x14, 0xDB}, // XK_parenright+AE11: VKEY_OEM_4
+ {0x0029, 0x23, 0xDD}, // XK_parenright+AD12: VKEY_OEM_6
+ {0x002A, 0x23, 0xBA}, // XK_asterisk+AD12: VKEY_OEM_1
+ {0x002A, 0x33, 0xDC}, // XK_asterisk+BKSL: VKEY_OEM_5
+ {0x002B, 0x0A, 0x31}, // XK_plus+AE01: VKEY_1
+ {0x002B, 0x15, 0xBB}, // XK_plus+AE12: VKEY_OEM_PLUS
+ {0x002B, 0x22, 0xBB}, // XK_plus+AD11: VKEY_OEM_PLUS
+ {0x002B, 0x23, 0xBB}, // XK_plus+AD12: VKEY_OEM_PLUS
+ {0x002B, 0x2F, 0xBB}, // XK_plus+AC10: VKEY_OEM_PLUS
+ {0x002B, 0x33, 0xBF}, // XK_plus+BKSL: VKEY_OEM_2
+ {0x002C, 0x0C, 0x33}, // XK_comma+AE03: VKEY_3
+ {0x002C, 0x0E, 0x35}, // XK_comma+AE05: VKEY_5
+ {0x002C, 0x0F, 0x36}, // XK_comma+AE06: VKEY_6
+ {0x002C, 0x12, 0x39}, // XK_comma+AE09: VKEY_9
+ {0x002C, 0x19, 0xBC}, // XK_comma+AD02: VKEY_OEM_COMMA
+ {0x002C, 0x30, 0xDE}, // XK_comma+AC11: VKEY_OEM_7
+ {0x002C, 0x37, 0xBC}, // XK_comma+AB04: VKEY_OEM_COMMA
+ {0x002C, 0x3A, 0xBC}, // XK_comma+AB07: VKEY_OEM_COMMA
+ {0x002C, 0x3B, 0xBC}, // XK_comma+AB08: VKEY_OEM_COMMA
+ {0x002D, 0x0B, 0x32}, // XK_minus+AE02: VKEY_2
+ {0x002D, 0x0F, 0x36}, // XK_minus+AE06: VKEY_6
+ {0x002D, 0x14, 0xBD}, // XK_minus+AE11: VKEY_OEM_MINUS
+ {0x002D, 0x26, 0xBD}, // XK_minus+AC01: VKEY_OEM_MINUS
+ {0x002D, 0x30, 0xBD}, // XK_minus+AC11: VKEY_OEM_MINUS
+ {0x002E, 0x10, 0x37}, // XK_period+AE07: VKEY_7
+ {0x002E, 0x11, 0x38}, // XK_period+AE08: VKEY_8
+ {0x002E, 0x1A, 0xBE}, // XK_period+AD03: VKEY_OEM_PERIOD
+ {0x002E, 0x1B, 0xBE}, // XK_period+AD04: VKEY_OEM_PERIOD
+ {0x002E, 0x20, 0xBE}, // XK_period+AD09: VKEY_OEM_PERIOD
+ {0x002E, 0x30, 0xDE}, // XK_period+AC11: VKEY_OEM_7
+ {0x002E, 0x3C, 0xBE}, // XK_period+AB09: VKEY_OEM_PERIOD
+ {0x002E, 0x3D, 0xBF}, // XK_period+AB10: VKEY_OEM_2
+ {0x002F, 0x14, 0xDB}, // XK_slash+AE11: VKEY_OEM_4
+ {0x002F, 0x18, 0x51}, // XK_slash+AD01: VKEY_Q
+ {0x002F, 0x22, 0xBF}, // XK_slash+AD11: VKEY_OEM_2
+ {0x002F, 0x31, 0xDE}, // XK_slash+TLDE: VKEY_OEM_7
+ {0x002F, 0x33, 0xDC}, // XK_slash+BKSL: VKEY_OEM_5
+ {0x002F, 0x3D, 0xBF}, // XK_slash+AB10: VKEY_OEM_2
+ {0x003A, 0x0A, 0x31}, // XK_colon+AE01: VKEY_1
+ {0x003A, 0x0E, 0x35}, // XK_colon+AE05: VKEY_5
+ {0x003A, 0x0F, 0x36}, // XK_colon+AE06: VKEY_6
+ {0x003A, 0x3C, 0xBF}, // XK_colon+AB09: VKEY_OEM_2
+ {0x003B, 0x0D, 0x34}, // XK_semicolon+AE04: VKEY_4
+ {0x003B, 0x11, 0x38}, // XK_semicolon+AE08: VKEY_8
+ {0x003B, 0x18, 0xBA}, // XK_semicolon+AD01: VKEY_OEM_1
+ {0x003B, 0x22, 0xBA}, // XK_semicolon+AD11: VKEY_OEM_1
+ {0x003B, 0x23, 0xDD}, // XK_semicolon+AD12: VKEY_OEM_6
+ {0x003B, 0x2F, 0xBA}, // XK_semicolon+AC10: VKEY_OEM_1
+ {0x003B, 0x31, 0xC0}, // XK_semicolon+TLDE: VKEY_OEM_3
+ {0x003B, 0x34, 0xBA}, // XK_semicolon+AB01: VKEY_OEM_1
+ {0x003B, 0x3B, 0xBE}, // XK_semicolon+AB08: VKEY_OEM_PERIOD
+ {0x003B, 0x3D, 0xBF}, // XK_semicolon+AB10: VKEY_OEM_2
+ {0x003D, 0x11, 0x38}, // XK_equal+AE08: VKEY_8
+ {0x003D, 0x15, 0xBB}, // XK_equal+AE12: VKEY_OEM_PLUS
+ {0x003D, 0x23, 0xBB}, // XK_equal+AD12: VKEY_OEM_PLUS
+ {0x003F, 0x0B, 0x32}, // XK_question+AE02: VKEY_2
+ {0x003F, 0x10, 0x37}, // XK_question+AE07: VKEY_7
+ {0x003F, 0x11, 0x38}, // XK_question+AE08: VKEY_8
+ {0x003F, 0x14, 0xBB}, // XK_question+AE11: VKEY_OEM_PLUS
+ {0x0040, 0x23, 0xDD}, // XK_at+AD12: VKEY_OEM_6
+ {0x0040, 0x31, 0xDE}, // XK_at+TLDE: VKEY_OEM_7
+ {0x005B, 0x0A, 0xDB}, // XK_bracketleft+AE01: VKEY_OEM_4
+ {0x005B, 0x14, 0xDB}, // XK_bracketleft+AE11: VKEY_OEM_4
+ {0x005B, 0x22, 0xDB}, // XK_bracketleft+AD11: VKEY_OEM_4
+ {0x005B, 0x23, 0xDD}, // XK_bracketleft+AD12: VKEY_OEM_6
+ {0x005B, 0x30, 0xDE}, // XK_bracketleft+AC11: VKEY_OEM_7
+ {0x005C, 0x15, 0xDB}, // XK_backslash+AE12: VKEY_OEM_4
+ {0x005D, 0x0B, 0xDD}, // XK_bracketright+AE02: VKEY_OEM_6
+ {0x005D, 0x15, 0xDD}, // XK_bracketright+AE12: VKEY_OEM_6
+ {0x005D, 0x22, 0xDB}, // XK_bracketright+AD11: VKEY_OEM_4
+ {0x005D, 0x23, 0xDD}, // XK_bracketright+AD12: VKEY_OEM_6
+ {0x005D, 0x31, 0xC0}, // XK_bracketright+TLDE: VKEY_OEM_3
+ {0x005D, 0x33, 0xDC}, // XK_bracketright+BKSL: VKEY_OEM_5
+ {0x005F, 0x11, 0x38}, // XK_underscore+AE08: VKEY_8
+ {0x005F, 0x14, 0xBD}, // XK_underscore+AE11: VKEY_OEM_MINUS
+ {0x00A7, 0x0D, 0x34}, // XK_section+AE04: VKEY_4
+ {0x00A7, 0x0F, 0x36}, // XK_section+AE06: VKEY_6
+ {0x00A7, 0x30, 0xDE}, // XK_section+AC11: VKEY_OEM_7
+ {0x00AB, 0x11, 0x38}, // XK_guillemotleft+AE08: VKEY_8
+ {0x00AB, 0x15, 0xDD}, // XK_guillemotleft+AE12: VKEY_OEM_6
+ {0x00B0, 0x15, 0xBF}, // XK_degree+AE12: VKEY_OEM_2
+ {0x00B0, 0x31, 0xDE}, // XK_degree+TLDE: VKEY_OEM_7
+ {0x00BA, 0x30, 0xDE}, // XK_masculine+AC11: VKEY_OEM_7
+ {0x00BA, 0x31, 0xDC}, // XK_masculine+TLDE: VKEY_OEM_5
+ {0x00E0, 0x13, 0x30}, // XK_agrave+AE10: VKEY_0
+ {0x00E0, 0x33, 0xDC}, // XK_agrave+BKSL: VKEY_OEM_5
+ {0x00E1, 0x11, 0x38}, // XK_aacute+AE08: VKEY_8
+ {0x00E1, 0x30, 0xDE}, // XK_aacute+AC11: VKEY_OEM_7
+ {0x00E2, 0x0B, 0x32}, // XK_acircumflex+AE02: VKEY_2
+ {0x00E2, 0x33, 0xDC}, // XK_acircumflex+BKSL: VKEY_OEM_5
+ {0x00E4, 0x23, 0xDD}, // XK_adiaeresis+AD12: VKEY_OEM_6
+ {0x00E6, 0x2F, 0xC0}, // XK_ae+AC10: VKEY_OEM_3
+ {0x00E6, 0x30, 0xDE}, // XK_ae+AC11: VKEY_OEM_7
+ {0x00E7, 0x12, 0x39}, // XK_ccedilla+AE09: VKEY_9
+ {0x00E7, 0x22, 0xDB}, // XK_ccedilla+AD11: VKEY_OEM_4
+ {0x00E7, 0x23, 0xDD}, // XK_ccedilla+AD12: VKEY_OEM_6
+ {0x00E7, 0x30, 0xDE}, // XK_ccedilla+AC11: VKEY_OEM_7
+ {0x00E7, 0x33, 0xBF}, // XK_ccedilla+BKSL: VKEY_OEM_2
+ {0x00E7, 0x3B, 0xBC}, // XK_ccedilla+AB08: VKEY_OEM_COMMA
+ {0x00E8, 0x10, 0x37}, // XK_egrave+AE07: VKEY_7
+ {0x00E8, 0x22, 0xBA}, // XK_egrave+AD11: VKEY_OEM_1
+ {0x00E8, 0x30, 0xC0}, // XK_egrave+AC11: VKEY_OEM_3
+ {0x00E9, 0x0B, 0x32}, // XK_eacute+AE02: VKEY_2
+ {0x00E9, 0x13, 0x30}, // XK_eacute+AE10: VKEY_0
+ {0x00E9, 0x3D, 0xBF}, // XK_eacute+AB10: VKEY_OEM_2
+ {0x00ED, 0x12, 0x39}, // XK_iacute+AE09: VKEY_9
+ {0x00ED, 0x31, 0x30}, // XK_iacute+TLDE: VKEY_0
+ {0x00F0, 0x22, 0xDD}, // XK_eth+AD11: VKEY_OEM_6
+ {0x00F0, 0x23, 0xBA}, // XK_eth+AD12: VKEY_OEM_1
+ {0x00F3, 0x15, 0xBB}, // XK_oacute+AE12: VKEY_OEM_PLUS
+ {0x00F3, 0x33, 0xDC}, // XK_oacute+BKSL: VKEY_OEM_5
+ {0x00F4, 0x0D, 0x34}, // XK_ocircumflex+AE04: VKEY_4
+ {0x00F4, 0x2F, 0xBA}, // XK_ocircumflex+AC10: VKEY_OEM_1
+ {0x00F6, 0x13, 0xC0}, // XK_odiaeresis+AE10: VKEY_OEM_3
+ {0x00F6, 0x14, 0xBB}, // XK_odiaeresis+AE11: VKEY_OEM_PLUS
+ {0x00F6, 0x22, 0xDB}, // XK_odiaeresis+AD11: VKEY_OEM_4
+ {0x00F8, 0x2F, 0xC0}, // XK_oslash+AC10: VKEY_OEM_3
+ {0x00F8, 0x30, 0xDE}, // XK_oslash+AC11: VKEY_OEM_7
+ {0x00F9, 0x30, 0xC0}, // XK_ugrave+AC11: VKEY_OEM_3
+ {0x00F9, 0x33, 0xBF}, // XK_ugrave+BKSL: VKEY_OEM_2
+ {0x00FA, 0x22, 0xDB}, // XK_uacute+AD11: VKEY_OEM_4
+ {0x00FA, 0x23, 0xDD}, // XK_uacute+AD12: VKEY_OEM_6
+ {0x00FC, 0x19, 0x57}, // XK_udiaeresis+AD02: VKEY_W
+ {0x01B1, 0x0A, 0x31}, // XK_aogonek+AE01: VKEY_1
+ {0x01B1, 0x18, 0x51}, // XK_aogonek+AD01: VKEY_Q
+ {0x01B1, 0x30, 0xDE}, // XK_aogonek+AC11: VKEY_OEM_7
+ {0x01B3, 0x2F, 0xBA}, // XK_lstroke+AC10: VKEY_OEM_1
+ {0x01B3, 0x33, 0xBF}, // XK_lstroke+BKSL: VKEY_OEM_2
+ {0x01B9, 0x0C, 0x33}, // XK_scaron+AE03: VKEY_3
+ {0x01B9, 0x0F, 0x36}, // XK_scaron+AE06: VKEY_6
+ {0x01B9, 0x22, 0xDB}, // XK_scaron+AD11: VKEY_OEM_4
+ {0x01B9, 0x26, 0xBA}, // XK_scaron+AC01: VKEY_OEM_1
+ {0x01B9, 0x29, 0x46}, // XK_scaron+AC04: VKEY_F
+ {0x01B9, 0x3C, 0xBE}, // XK_scaron+AB09: VKEY_OEM_PERIOD
+ {0x01BA, 0x2F, 0xBA}, // XK_scedilla+AC10: VKEY_OEM_1
+ {0x01BA, 0x3C, 0xBE}, // XK_scedilla+AB09: VKEY_OEM_PERIOD
+ {0x01BE, 0x0F, 0x36}, // XK_zcaron+AE06: VKEY_6
+ {0x01BE, 0x15, 0xBB}, // XK_zcaron+AE12: VKEY_OEM_PLUS
+ {0x01BE, 0x19, 0x57}, // XK_zcaron+AD02: VKEY_W
+ {0x01BE, 0x22, 0x59}, // XK_zcaron+AD11: VKEY_Y
+ {0x01BE, 0x33, 0xDC}, // XK_zcaron+BKSL: VKEY_OEM_5
+ {0x01BF, 0x22, 0xDB}, // XK_zabovedot+AD11: VKEY_OEM_4
+ {0x01BF, 0x33, 0xDC}, // XK_zabovedot+BKSL: VKEY_OEM_5
+ {0x01E3, 0x0A, 0x31}, // XK_abreve+AE01: VKEY_1
+ {0x01E3, 0x22, 0xDB}, // XK_abreve+AD11: VKEY_OEM_4
+ {0x01E8, 0x0B, 0x32}, // XK_ccaron+AE02: VKEY_2
+ {0x01E8, 0x0D, 0x34}, // XK_ccaron+AE04: VKEY_4
+ {0x01E8, 0x21, 0x58}, // XK_ccaron+AD10: VKEY_X
+ {0x01E8, 0x2F, 0xBA}, // XK_ccaron+AC10: VKEY_OEM_1
+ {0x01E8, 0x3B, 0xBC}, // XK_ccaron+AB08: VKEY_OEM_COMMA
+ {0x01EA, 0x0C, 0x33}, // XK_eogonek+AE03: VKEY_3
+ {0x01F0, 0x13, 0x30}, // XK_dstroke+AE10: VKEY_0
+ {0x01F0, 0x23, 0xDD}, // XK_dstroke+AD12: VKEY_OEM_6
+ {0x03E7, 0x0E, 0x35}, // XK_iogonek+AE05: VKEY_5
+ {0x03EC, 0x0D, 0x34}, // XK_eabovedot+AE04: VKEY_4
+ {0x03EC, 0x30, 0xDE}, // XK_eabovedot+AC11: VKEY_OEM_7
+ {0x03F9, 0x10, 0x37}, // XK_uogonek+AE07: VKEY_7
+ {0x03FE, 0x11, 0x38}, // XK_umacron+AE08: VKEY_8
+ {0x03FE, 0x18, 0x51}, // XK_umacron+AD01: VKEY_Q
+ {0x03FE, 0x35, 0x58}, // XK_umacron+AB02: VKEY_X
};
const struct MAP2 {
@@ -326,7 +404,6 @@ const struct MAP2 {
{0x002F, 0x13, 0x003F, 0xBF}, // XK_slash+AE10+XK_question: VKEY_OEM_2
{0x003D, 0x3D, 0x0025, 0xDF}, // XK_equal+AB10+XK_percent: VKEY_OEM_8
{0x003D, 0x3D, 0x002B, 0xBB}, // XK_equal+AB10+XK_plus: VKEY_OEM_PLUS
- {0x005C, 0x33, 0x002F, 0xDE}, // XK_backslash+BKSL+XK_slash: VKEY_OEM_7
{0x005C, 0x33, 0x007C, 0xDC}, // XK_backslash+BKSL+XK_bar: VKEY_OEM_5
{0x0060, 0x31, 0x0000, 0xC0}, // XK_quoteleft+TLDE+NoSymbol: VKEY_OEM_3
{0x0060, 0x31, 0x00AC, 0xDF}, // XK_quoteleft+TLDE+XK_notsign: VKEY_OEM_8
@@ -357,94 +434,98 @@ const struct MAP3 {
return m1.ch0 < m2.ch0;
}
} map3[] = {
- {0x0023, 0x33, 0x007E, 0x0000,
- 0xDE}, // XK_numbersign+BKSL+XK_asciitilde+NoSymbol: VKEY_OEM_7
- {0x0027, 0x14, 0x003F, 0x0000,
- 0xDB}, // XK_quoteright+AE11+XK_question+NoSymbol: VKEY_OEM_4
- {0x0027, 0x14, 0x003F, 0x00DD,
- 0xDB}, // XK_quoteright+AE11+XK_question+XK_Yacute: VKEY_OEM_4
- {0x0027, 0x15, 0x002A, 0x0000,
- 0xBB}, // XK_quoteright+AE12+XK_asterisk+NoSymbol: VKEY_OEM_PLUS
- {0x0027, 0x30, 0x0040, 0x0000,
- 0xC0}, // XK_quoteright+AC11+XK_at+NoSymbol: VKEY_OEM_3
- {0x0027, 0x33, 0x002A, 0x0000,
- 0xBF}, // XK_quoteright+BKSL+XK_asterisk+NoSymbol: VKEY_OEM_2
- {0x0027, 0x33, 0x002A, 0x00BD,
- 0xDC}, // XK_quoteright+BKSL+XK_asterisk+XK_onehalf: VKEY_OEM_5
- {0x0027, 0x33, 0x002A, 0x01A3,
- 0xBF}, // XK_quoteright+BKSL+XK_asterisk+XK_Lstroke: VKEY_OEM_2
- {0x0027, 0x34, 0x0022, 0x0000,
- 0x5A}, // XK_quoteright+AB01+XK_quotedbl+NoSymbol: VKEY_Z
- {0x0027, 0x34, 0x0022, 0x01D8,
- 0xDE}, // XK_quoteright+AB01+XK_quotedbl+XK_Rcaron: VKEY_OEM_7
- {0x002B, 0x14, 0x003F, 0x0000,
- 0xBB}, // XK_plus+AE11+XK_question+NoSymbol: VKEY_OEM_PLUS
- {0x002B, 0x14, 0x003F, 0x005C,
- 0xBD}, // XK_plus+AE11+XK_question+XK_backslash: VKEY_OEM_MINUS
- {0x002B, 0x14, 0x003F, 0x01F5,
- 0xBB}, // XK_plus+AE11+XK_question+XK_odoubleacute: VKEY_OEM_PLUS
- {0x002D, 0x15, 0x005F, 0x0000,
- 0xBD}, // XK_minus+AE12+XK_underscore+NoSymbol: VKEY_OEM_MINUS
- {0x002D, 0x15, 0x005F, 0x03B3,
- 0xDB}, // XK_minus+AE12+XK_underscore+XK_rcedilla: VKEY_OEM_4
- {0x002D, 0x3D, 0x005F, 0x0000,
- 0xBD}, // XK_minus+AB10+XK_underscore+NoSymbol: VKEY_OEM_MINUS
- {0x002D, 0x3D, 0x005F, 0x002A,
- 0xBD}, // XK_minus+AB10+XK_underscore+XK_asterisk: VKEY_OEM_MINUS
- {0x002D, 0x3D, 0x005F, 0x002F,
- 0xBF}, // XK_minus+AB10+XK_underscore+XK_slash: VKEY_OEM_2
- {0x002D, 0x3D, 0x005F, 0x006E,
- 0xBD}, // XK_minus+AB10+XK_underscore+XK_n: VKEY_OEM_MINUS
- {0x003D, 0x14, 0x0025, 0x0000,
- 0xBB}, // XK_equal+AE11+XK_percent+NoSymbol: VKEY_OEM_PLUS
- {0x003D, 0x14, 0x0025, 0x002D,
- 0xBD}, // XK_equal+AE11+XK_percent+XK_minus: VKEY_OEM_MINUS
- {0x005C, 0x31, 0x007C, 0x0031,
- 0xDC}, // XK_backslash+TLDE+XK_bar+XK_1: VKEY_OEM_5
- {0x005C, 0x31, 0x007C, 0x03D1,
- 0xC0}, // XK_backslash+TLDE+XK_bar+XK_Ncedilla: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x0000,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+NoSymbol: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x0031,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_1: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x003B,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_semicolon: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x0060,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_quoteleft: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x00BF,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_questiondown: VKEY_OEM_3
- {0x0060, 0x31, 0x007E, 0x01F5,
- 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_odoubleacute: VKEY_OEM_3
- {0x00E4, 0x30, 0x00C4, 0x0000,
- 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+NoSymbol: VKEY_OEM_7
- {0x00E4, 0x30, 0x00C4, 0x01A6,
- 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+XK_Sacute: VKEY_OEM_7
- {0x00E4, 0x30, 0x00C4, 0x01F8,
- 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+XK_rcaron: VKEY_OEM_7
- {0x00E7, 0x2F, 0x00C7, 0x0000,
- 0xBA}, // XK_ccedilla+AC10+XK_Ccedilla+NoSymbol: VKEY_OEM_1
- {0x00E7, 0x2F, 0x00C7, 0x00DE,
- 0xC0}, // XK_ccedilla+AC10+XK_Ccedilla+XK_Thorn: VKEY_OEM_3
- {0x00F6, 0x2F, 0x00D6, 0x0000,
- 0xC0}, // XK_odiaeresis+AC10+XK_Odiaeresis+NoSymbol: VKEY_OEM_3
- {0x00F6, 0x2F, 0x00D6, 0x01DE,
- 0xC0}, // XK_odiaeresis+AC10+XK_Odiaeresis+XK_Tcedilla: VKEY_OEM_3
- {0x00FC, 0x14, 0x00DC, 0x0000,
- 0xBF}, // XK_udiaeresis+AE11+XK_Udiaeresis+NoSymbol: VKEY_OEM_2
- {0x00FC, 0x22, 0x00DC, 0x0000,
- 0xBA}, // XK_udiaeresis+AD11+XK_Udiaeresis+NoSymbol: VKEY_OEM_1
- {0x00FC, 0x22, 0x00DC, 0x01A3,
- 0xC0}, // XK_udiaeresis+AD11+XK_Udiaeresis+XK_Lstroke: VKEY_OEM_3
- {0x01EA, 0x3D, 0x01CA, 0x0000,
- 0xBD}, // XK_eogonek+AB10+XK_Eogonek+NoSymbol: VKEY_OEM_MINUS
- {0x01EA, 0x3D, 0x01CA, 0x006E,
- 0xBF}, // XK_eogonek+AB10+XK_Eogonek+XK_n: VKEY_OEM_2
- {0x03E7, 0x22, 0x03C7, 0x0000,
- 0xDB}, // XK_iogonek+AD11+XK_Iogonek+NoSymbol: VKEY_OEM_4
- {0x03F9, 0x2F, 0x03D9, 0x0000,
- 0xC0}, // XK_uogonek+AC10+XK_Uogonek+NoSymbol: VKEY_OEM_3
- {0x03F9, 0x2F, 0x03D9, 0x01DE,
- 0xBA}, // XK_uogonek+AC10+XK_Uogonek+XK_Tcedilla: VKEY_OEM_1
+ {0x0023, 0x33, 0x007E, 0x0000,
+ 0xDE}, // XK_numbersign+BKSL+XK_asciitilde+NoSymbol: VKEY_OEM_7
+ {0x0027, 0x14, 0x003F, 0x0000,
+ 0xDB}, // XK_quoteright+AE11+XK_question+NoSymbol: VKEY_OEM_4
+ {0x0027, 0x14, 0x003F, 0x00DD,
+ 0xDB}, // XK_quoteright+AE11+XK_question+XK_Yacute: VKEY_OEM_4
+ {0x0027, 0x15, 0x002A, 0x0000,
+ 0xBB}, // XK_quoteright+AE12+XK_asterisk+NoSymbol: VKEY_OEM_PLUS
+ {0x0027, 0x30, 0x0040, 0x0000,
+ 0xC0}, // XK_quoteright+AC11+XK_at+NoSymbol: VKEY_OEM_3
+ {0x0027, 0x33, 0x002A, 0x0000,
+ 0xBF}, // XK_quoteright+BKSL+XK_asterisk+NoSymbol: VKEY_OEM_2
+ {0x0027, 0x33, 0x002A, 0x00BD,
+ 0xDC}, // XK_quoteright+BKSL+XK_asterisk+XK_onehalf: VKEY_OEM_5
+ {0x0027, 0x33, 0x002A, 0x01A3,
+ 0xBF}, // XK_quoteright+BKSL+XK_asterisk+XK_Lstroke: VKEY_OEM_2
+ {0x0027, 0x34, 0x0022, 0x0000,
+ 0x5A}, // XK_quoteright+AB01+XK_quotedbl+NoSymbol: VKEY_Z
+ {0x0027, 0x34, 0x0022, 0x01D8,
+ 0xDE}, // XK_quoteright+AB01+XK_quotedbl+XK_Rcaron: VKEY_OEM_7
+ {0x002B, 0x14, 0x003F, 0x0000,
+ 0xBB}, // XK_plus+AE11+XK_question+NoSymbol: VKEY_OEM_PLUS
+ {0x002B, 0x14, 0x003F, 0x005C,
+ 0xBD}, // XK_plus+AE11+XK_question+XK_backslash: VKEY_OEM_MINUS
+ {0x002B, 0x14, 0x003F, 0x01F5,
+ 0xBB}, // XK_plus+AE11+XK_question+XK_odoubleacute: VKEY_OEM_PLUS
+ {0x002D, 0x15, 0x005F, 0x0000,
+ 0xBD}, // XK_minus+AE12+XK_underscore+NoSymbol: VKEY_OEM_MINUS
+ {0x002D, 0x15, 0x005F, 0x03B3,
+ 0xDB}, // XK_minus+AE12+XK_underscore+XK_rcedilla: VKEY_OEM_4
+ {0x002D, 0x3D, 0x005F, 0x0000,
+ 0xBD}, // XK_minus+AB10+XK_underscore+NoSymbol: VKEY_OEM_MINUS
+ {0x002D, 0x3D, 0x005F, 0x002A,
+ 0xBD}, // XK_minus+AB10+XK_underscore+XK_asterisk: VKEY_OEM_MINUS
+ {0x002D, 0x3D, 0x005F, 0x002F,
+ 0xBF}, // XK_minus+AB10+XK_underscore+XK_slash: VKEY_OEM_2
+ {0x002D, 0x3D, 0x005F, 0x006E,
+ 0xBD}, // XK_minus+AB10+XK_underscore+XK_n: VKEY_OEM_MINUS
+ {0x003D, 0x14, 0x0025, 0x0000,
+ 0xBB}, // XK_equal+AE11+XK_percent+NoSymbol: VKEY_OEM_PLUS
+ {0x003D, 0x14, 0x0025, 0x002D,
+ 0xBD}, // XK_equal+AE11+XK_percent+XK_minus: VKEY_OEM_MINUS
+ {0x005C, 0x31, 0x007C, 0x0031,
+ 0xDC}, // XK_backslash+TLDE+XK_bar+XK_1: VKEY_OEM_5
+ {0x005C, 0x31, 0x007C, 0x03D1,
+ 0xC0}, // XK_backslash+TLDE+XK_bar+XK_Ncedilla: VKEY_OEM_3
+ {0x005C, 0x33, 0x002F, 0x0000,
+ 0xDC}, // XK_backslash+BKSL+XK_slash+NoSymbol: VKEY_OEM_5
+ {0x005C, 0x33, 0x002F, 0x01A3,
+ 0xDE}, // XK_backslash+BKSL+XK_slash+XK_Lstroke: VKEY_OEM_7
+ {0x0060, 0x31, 0x007E, 0x0000,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+NoSymbol: VKEY_OEM_3
+ {0x0060, 0x31, 0x007E, 0x0031,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_1: VKEY_OEM_3
+ {0x0060, 0x31, 0x007E, 0x003B,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_semicolon: VKEY_OEM_3
+ {0x0060, 0x31, 0x007E, 0x0060,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_quoteleft: VKEY_OEM_3
+ {0x0060, 0x31, 0x007E, 0x00BF,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_questiondown: VKEY_OEM_3
+ {0x0060, 0x31, 0x007E, 0x01F5,
+ 0xC0}, // XK_quoteleft+TLDE+XK_asciitilde+XK_odoubleacute: VKEY_OEM_3
+ {0x00E4, 0x30, 0x00C4, 0x0000,
+ 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+NoSymbol: VKEY_OEM_7
+ {0x00E4, 0x30, 0x00C4, 0x01A6,
+ 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+XK_Sacute: VKEY_OEM_7
+ {0x00E4, 0x30, 0x00C4, 0x01F8,
+ 0xDE}, // XK_adiaeresis+AC11+XK_Adiaeresis+XK_rcaron: VKEY_OEM_7
+ {0x00E7, 0x2F, 0x00C7, 0x0000,
+ 0xBA}, // XK_ccedilla+AC10+XK_Ccedilla+NoSymbol: VKEY_OEM_1
+ {0x00E7, 0x2F, 0x00C7, 0x00DE,
+ 0xC0}, // XK_ccedilla+AC10+XK_Ccedilla+XK_Thorn: VKEY_OEM_3
+ {0x00F6, 0x2F, 0x00D6, 0x0000,
+ 0xC0}, // XK_odiaeresis+AC10+XK_Odiaeresis+NoSymbol: VKEY_OEM_3
+ {0x00F6, 0x2F, 0x00D6, 0x01DE,
+ 0xC0}, // XK_odiaeresis+AC10+XK_Odiaeresis+XK_Tcedilla: VKEY_OEM_3
+ {0x00FC, 0x14, 0x00DC, 0x0000,
+ 0xBF}, // XK_udiaeresis+AE11+XK_Udiaeresis+NoSymbol: VKEY_OEM_2
+ {0x00FC, 0x22, 0x00DC, 0x0000,
+ 0xBA}, // XK_udiaeresis+AD11+XK_Udiaeresis+NoSymbol: VKEY_OEM_1
+ {0x00FC, 0x22, 0x00DC, 0x01A3,
+ 0xC0}, // XK_udiaeresis+AD11+XK_Udiaeresis+XK_Lstroke: VKEY_OEM_3
+ {0x01EA, 0x3D, 0x01CA, 0x0000,
+ 0xBD}, // XK_eogonek+AB10+XK_Eogonek+NoSymbol: VKEY_OEM_MINUS
+ {0x01EA, 0x3D, 0x01CA, 0x006E,
+ 0xBF}, // XK_eogonek+AB10+XK_Eogonek+XK_n: VKEY_OEM_2
+ {0x03E7, 0x22, 0x03C7, 0x0000,
+ 0xDB}, // XK_iogonek+AD11+XK_Iogonek+NoSymbol: VKEY_OEM_4
+ {0x03F9, 0x2F, 0x03D9, 0x0000,
+ 0xC0}, // XK_uogonek+AC10+XK_Uogonek+NoSymbol: VKEY_OEM_3
+ {0x03F9, 0x2F, 0x03D9, 0x01DE,
+ 0xBA}, // XK_uogonek+AC10+XK_Uogonek+XK_Tcedilla: VKEY_OEM_1
};
template <class T_MAP>
diff --git a/chromium/ui/events/keycodes/platform_key_map_win.cc b/chromium/ui/events/keycodes/platform_key_map_win.cc
index d7ecacc8553..fd694a984b7 100644
--- a/chromium/ui/events/keycodes/platform_key_map_win.cc
+++ b/chromium/ui/events/keycodes/platform_key_map_win.cc
@@ -279,7 +279,7 @@ base::LazyInstance<base::ThreadLocalStorage::Slot,
// TODO(crbug.com/25503): Controls Control+Alt vs AltGraph disambiguation.
const base::Feature kFixAltGraphModifier{"FixAltGraph",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // anonymous namespace
diff --git a/chromium/ui/events/keycodes/platform_key_map_win.h b/chromium/ui/events/keycodes/platform_key_map_win.h
index 53e13ba090f..6d8cfa560d3 100644
--- a/chromium/ui/events/keycodes/platform_key_map_win.h
+++ b/chromium/ui/events/keycodes/platform_key_map_win.h
@@ -9,12 +9,12 @@
#include <unordered_map>
-#include "base/event_types.h"
#include "base/hash.h"
#include "ui/events/event.h"
#include "ui/events/events_export.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_codes_win.h"
+#include "ui/events/platform_event.h"
namespace ui {
diff --git a/chromium/ui/events/mojo/BUILD.gn b/chromium/ui/events/mojo/BUILD.gn
index 49165b33496..9515ba479c4 100644
--- a/chromium/ui/events/mojo/BUILD.gn
+++ b/chromium/ui/events/mojo/BUILD.gn
@@ -12,7 +12,7 @@ mojom("interfaces") {
]
public_deps = [
- "//mojo/common:common_custom_types",
+ "//mojo/public/mojom/base",
"//ui/gfx/mojo",
"//ui/latency/mojo:interfaces",
]
diff --git a/chromium/ui/events/mojo/event.mojom b/chromium/ui/events/mojo/event.mojom
index 6670751117a..b68dff4550b 100644
--- a/chromium/ui/events/mojo/event.mojom
+++ b/chromium/ui/events/mojo/event.mojom
@@ -4,7 +4,7 @@
module ui.mojom;
-import "mojo/common/time.mojom";
+import "mojo/public/mojom/base/time.mojom";
import "ui/events/mojo/event_constants.mojom";
import "ui/events/mojo/keyboard_codes.mojom";
import "ui/latency/mojo/latency_info.mojom";
@@ -122,6 +122,27 @@ struct GestureData {
LocationData location;
};
+// Data to support scroll events.
+struct ScrollData {
+ LocationData location;
+
+ // Potential accelerated offsets.
+ float x_offset;
+ float y_offset;
+ // Unaccelerated offsets.
+ float x_offset_ordinal;
+ float y_offset_ordinal;
+ // Number of fingers on the pad.
+ int32 finger_count;
+
+ // For non-fling events, provides momentum information (e.g. for the case
+ // where the device provides continuous event updates during a fling).
+ EventMomentumPhase momentum_phase;
+
+ // Provides phase information if device can provide.
+ ScrollEventPhase scroll_event_phase;
+};
+
struct Event {
// TODO(sky): rename to type.
EventType action;
@@ -133,9 +154,10 @@ struct Event {
// This value accurately orders events w.r.t. to each other but does not
// position them at an absolute time since the TimeTicks origin is only
// guaranteed to be fixed during one instance of the application.
- mojo.common.mojom.TimeTicks time_stamp;
+ mojo_base.mojom.TimeTicks time_stamp;
LatencyInfo latency;
KeyData? key_data;
PointerData? pointer_data;
GestureData? gesture_data;
+ ScrollData? scroll_data;
};
diff --git a/chromium/ui/events/mojo/event.typemap b/chromium/ui/events/mojo/event.typemap
index d4a0fc65357..a294ca2a71d 100644
--- a/chromium/ui/events/mojo/event.typemap
+++ b/chromium/ui/events/mojo/event.typemap
@@ -7,7 +7,6 @@ public_headers = [ "//ui/events/event.h" ]
traits_headers = [ "//ui/events/mojo/event_struct_traits.h" ]
public_deps = [
"//mojo/common:common_custom_types",
- "//mojo/common:struct_traits",
"//ui/events",
"//ui/events:dom_keycode_converter",
"//ui/latency/mojo:interfaces",
@@ -21,4 +20,8 @@ sources = [
]
# TODO(moshayedi): crbug.com/617167. Map mojom.Event directly to ui::Event.
-type_mappings = [ "ui.mojom.Event=std::unique_ptr<ui::Event>[move_only]" ]
+type_mappings = [
+ "ui.mojom.Event=std::unique_ptr<ui::Event>[move_only]",
+ "ui.mojom.EventMomentumPhase=ui::EventMomentumPhase",
+ "ui.mojom.ScrollEventPhase=ui::ScrollEventPhase",
+]
diff --git a/chromium/ui/events/mojo/event_constants.mojom b/chromium/ui/events/mojo/event_constants.mojom
index 74ba1dcfd50..f7b27bd9059 100644
--- a/chromium/ui/events/mojo/event_constants.mojom
+++ b/chromium/ui/events/mojo/event_constants.mojom
@@ -23,6 +23,9 @@ enum EventType {
POINTER_WHEEL_CHANGED,
MOUSE_EXIT,
GESTURE_TAP,
+ SCROLL,
+ SCROLL_FLING_START,
+ SCROLL_FLING_CANCEL,
};
// This mirrors ui::EventFlags
@@ -63,3 +66,22 @@ enum WheelMode {
PAGE,
SCALING,
};
+
+// Phase information used for a ScrollEvent.
+// These values match ui::ScrollEventPhase in ui/events/event_constants.h
+enum ScrollEventPhase {
+ kNone,
+ kBegan,
+ kUpdate,
+ kEnd,
+};
+
+// Momentum phase information used for a ScrollEvent.
+// These values match ui::EventMomentumPhase in ui/events/event_constants.h
+enum EventMomentumPhase {
+ NONE,
+ BEGAN,
+ MAY_BEGIN,
+ INERTIAL_UPDATE,
+ END,
+}; \ No newline at end of file
diff --git a/chromium/ui/events/mojo/event_struct_traits.cc b/chromium/ui/events/mojo/event_struct_traits.cc
index 0be3b783d48..1dd08b6f907 100644
--- a/chromium/ui/events/mojo/event_struct_traits.cc
+++ b/chromium/ui/events/mojo/event_struct_traits.cc
@@ -4,7 +4,7 @@
#include "ui/events/mojo/event_struct_traits.h"
-#include "mojo/common/time_struct_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "ui/events/event.h"
#include "ui/events/gesture_event_details.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
@@ -43,6 +43,15 @@ ui::mojom::EventType UIEventTypeToMojo(ui::EventType type) {
case ui::ET_GESTURE_TAP:
return ui::mojom::EventType::GESTURE_TAP;
+ case ui::ET_SCROLL:
+ return ui::mojom::EventType::SCROLL;
+
+ case ui::ET_SCROLL_FLING_START:
+ return ui::mojom::EventType::SCROLL_FLING_START;
+
+ case ui::ET_SCROLL_FLING_CANCEL:
+ return ui::mojom::EventType::SCROLL_FLING_CANCEL;
+
default:
NOTREACHED() << "This unsupported event type will close the connection";
break;
@@ -70,6 +79,15 @@ ui::EventType MojoPointerEventTypeToUIEvent(ui::mojom::EventType action) {
case ui::mojom::EventType::POINTER_WHEEL_CHANGED:
return ui::ET_POINTER_WHEEL_CHANGED;
+ case ui::mojom::EventType::SCROLL:
+ return ui::ET_SCROLL;
+
+ case ui::mojom::EventType::SCROLL_FLING_START:
+ return ui::ET_SCROLL_FLING_START;
+
+ case ui::mojom::EventType::SCROLL_FLING_CANCEL:
+ return ui::ET_SCROLL_FLING_CANCEL;
+
default:
NOTREACHED();
}
@@ -77,7 +95,7 @@ ui::EventType MojoPointerEventTypeToUIEvent(ui::mojom::EventType action) {
return ui::ET_UNKNOWN;
}
-ui::mojom::LocationDataPtr GetLocationData(ui::LocatedEvent* event) {
+ui::mojom::LocationDataPtr GetLocationData(const ui::LocatedEvent* event) {
ui::mojom::LocationDataPtr location_data(ui::mojom::LocationData::New());
location_data->x = event->location_f().x();
location_data->y = event->location_f().y();
@@ -319,6 +337,24 @@ StructTraits<ui::mojom::EventDataView, EventUniquePtr>::gesture_data(
return gesture_data;
}
+ui::mojom::ScrollDataPtr
+StructTraits<ui::mojom::EventDataView, EventUniquePtr>::scroll_data(
+ const EventUniquePtr& event) {
+ if (!event->IsScrollEvent())
+ return nullptr;
+
+ ui::mojom::ScrollDataPtr scroll_data(ui::mojom::ScrollData::New());
+ scroll_data->location = GetLocationData(event->AsLocatedEvent());
+ const ui::ScrollEvent* scroll_event = event->AsScrollEvent();
+ scroll_data->x_offset = scroll_event->x_offset();
+ scroll_data->y_offset = scroll_event->y_offset();
+ scroll_data->x_offset_ordinal = scroll_event->x_offset_ordinal();
+ scroll_data->y_offset_ordinal = scroll_event->y_offset_ordinal();
+ scroll_data->finger_count = scroll_event->finger_count();
+ scroll_data->momentum_phase = scroll_event->momentum_phase();
+ return scroll_data;
+}
+
bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
ui::mojom::EventDataView event,
EventUniquePtr* out) {
@@ -386,6 +422,22 @@ bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
time_stamp, ui::GestureEventDetails(ui::ET_GESTURE_TAP));
break;
}
+ case ui::mojom::EventType::SCROLL:
+ case ui::mojom::EventType::SCROLL_FLING_START:
+ case ui::mojom::EventType::SCROLL_FLING_CANCEL: {
+ ui::mojom::ScrollDataPtr scroll_data;
+ if (!event.ReadScrollData<ui::mojom::ScrollDataPtr>(&scroll_data))
+ return false;
+
+ *out = std::make_unique<ui::ScrollEvent>(
+ MojoPointerEventTypeToUIEvent(event.action()),
+ gfx::Point(scroll_data->location->x, scroll_data->location->y),
+ time_stamp, event.flags(), scroll_data->x_offset,
+ scroll_data->y_offset, scroll_data->x_offset_ordinal,
+ scroll_data->y_offset_ordinal, scroll_data->finger_count,
+ scroll_data->momentum_phase);
+ break;
+ }
case ui::mojom::EventType::UNKNOWN:
NOTREACHED() << "This unsupported event type will close the connection";
return false;
diff --git a/chromium/ui/events/mojo/event_struct_traits.h b/chromium/ui/events/mojo/event_struct_traits.h
index 474365cf258..0699a69ed45 100644
--- a/chromium/ui/events/mojo/event_struct_traits.h
+++ b/chromium/ui/events/mojo/event_struct_traits.h
@@ -5,7 +5,9 @@
#ifndef UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
#define UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
+#include "ui/events/event_constants.h"
#include "ui/events/mojo/event.mojom.h"
+#include "ui/events/mojo/event_constants.mojom.h"
namespace ui {
class Event;
@@ -25,9 +27,91 @@ struct StructTraits<ui::mojom::EventDataView, EventUniquePtr> {
static ui::mojom::KeyDataPtr key_data(const EventUniquePtr& event);
static ui::mojom::PointerDataPtr pointer_data(const EventUniquePtr& event);
static ui::mojom::GestureDataPtr gesture_data(const EventUniquePtr& event);
+ static ui::mojom::ScrollDataPtr scroll_data(const EventUniquePtr& event);
static bool Read(ui::mojom::EventDataView r, EventUniquePtr* out);
};
+template <>
+struct EnumTraits<ui::mojom::EventMomentumPhase, ui::EventMomentumPhase> {
+ static ui::mojom::EventMomentumPhase ToMojom(ui::EventMomentumPhase input) {
+ switch (input) {
+ case ui::EventMomentumPhase::NONE:
+ return ui::mojom::EventMomentumPhase::NONE;
+ case ui::EventMomentumPhase::BEGAN:
+ return ui::mojom::EventMomentumPhase::BEGAN;
+ case ui::EventMomentumPhase::MAY_BEGIN:
+ return ui::mojom::EventMomentumPhase::MAY_BEGIN;
+ case ui::EventMomentumPhase::INERTIAL_UPDATE:
+ return ui::mojom::EventMomentumPhase::INERTIAL_UPDATE;
+ case ui::EventMomentumPhase::END:
+ return ui::mojom::EventMomentumPhase::END;
+ }
+ NOTREACHED();
+ return ui::mojom::EventMomentumPhase::NONE;
+ }
+
+ static bool FromMojom(ui::mojom::EventMomentumPhase input,
+ ui::EventMomentumPhase* out) {
+ switch (input) {
+ case ui::mojom::EventMomentumPhase::NONE:
+ *out = ui::EventMomentumPhase::NONE;
+ return true;
+ case ui::mojom::EventMomentumPhase::BEGAN:
+ *out = ui::EventMomentumPhase::BEGAN;
+ return true;
+ case ui::mojom::EventMomentumPhase::MAY_BEGIN:
+ *out = ui::EventMomentumPhase::MAY_BEGIN;
+ return true;
+ case ui::mojom::EventMomentumPhase::INERTIAL_UPDATE:
+ *out = ui::EventMomentumPhase::INERTIAL_UPDATE;
+ return true;
+ case ui::mojom::EventMomentumPhase::END:
+ *out = ui::EventMomentumPhase::END;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<ui::mojom::ScrollEventPhase, ui::ScrollEventPhase> {
+ static ui::mojom::ScrollEventPhase ToMojom(ui::ScrollEventPhase input) {
+ switch (input) {
+ case ui::ScrollEventPhase::kNone:
+ return ui::mojom::ScrollEventPhase::kNone;
+ case ui::ScrollEventPhase::kBegan:
+ return ui::mojom::ScrollEventPhase::kBegan;
+ case ui::ScrollEventPhase::kUpdate:
+ return ui::mojom::ScrollEventPhase::kUpdate;
+ case ui::ScrollEventPhase::kEnd:
+ return ui::mojom::ScrollEventPhase::kEnd;
+ }
+ NOTREACHED();
+ return ui::mojom::ScrollEventPhase::kNone;
+ }
+
+ static bool FromMojom(ui::mojom::ScrollEventPhase input,
+ ui::ScrollEventPhase* out) {
+ switch (input) {
+ case ui::mojom::ScrollEventPhase::kNone:
+ *out = ui::ScrollEventPhase::kNone;
+ return true;
+ case ui::mojom::ScrollEventPhase::kBegan:
+ *out = ui::ScrollEventPhase::kBegan;
+ return true;
+ case ui::mojom::ScrollEventPhase::kUpdate:
+ *out = ui::ScrollEventPhase::kUpdate;
+ return true;
+ case ui::mojom::ScrollEventPhase::kEnd:
+ *out = ui::ScrollEventPhase::kEnd;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+};
+
} // namespace mojo
#endif // UI_EVENTS_MOJO_EVENT_STRUCT_TRAITS_H_
diff --git a/chromium/ui/events/mojo/struct_traits_unittest.cc b/chromium/ui/events/mojo/struct_traits_unittest.cc
index 90c1eddfced..4d136690dca 100644
--- a/chromium/ui/events/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/events/mojo/struct_traits_unittest.cc
@@ -5,7 +5,7 @@
#include <utility>
#include "base/message_loop/message_loop.h"
-#include "mojo/common/time_struct_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
@@ -250,4 +250,59 @@ TEST_F(StructTraitsTest, GestureEvent) {
}
}
+TEST_F(StructTraitsTest, ScrollEvent) {
+ ScrollEvent kTestData[] = {
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::NONE, ScrollEventPhase::kNone},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::NONE, ScrollEventPhase::kUpdate},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::NONE, ScrollEventPhase::kBegan},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::NONE, ScrollEventPhase::kEnd},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::BEGAN, ScrollEventPhase::kNone},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::INERTIAL_UPDATE,
+ ScrollEventPhase::kNone},
+ {ET_SCROLL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::END, ScrollEventPhase::kNone},
+ {ET_SCROLL_FLING_START, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(502), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::MAY_BEGIN, ScrollEventPhase::kNone},
+ {ET_SCROLL_FLING_CANCEL, gfx::Point(10, 20),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(502), EF_NONE, 1,
+ 2, 3, 4, 5, EventMomentumPhase::END, ScrollEventPhase::kNone},
+ };
+
+ mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
+ for (size_t i = 0; i < arraysize(kTestData); i++) {
+ std::unique_ptr<Event> output;
+ proxy->EchoEvent(Event::Clone(kTestData[i]), &output);
+ EXPECT_TRUE(output->IsScrollEvent());
+
+ const ScrollEvent* output_ptr_event = output->AsScrollEvent();
+ EXPECT_EQ(kTestData[i].type(), output_ptr_event->type());
+ EXPECT_EQ(kTestData[i].location(), output_ptr_event->location());
+ EXPECT_EQ(kTestData[i].time_stamp(), output_ptr_event->time_stamp());
+ EXPECT_EQ(kTestData[i].flags(), output_ptr_event->flags());
+ EXPECT_EQ(kTestData[i].x_offset(), output_ptr_event->x_offset());
+ EXPECT_EQ(kTestData[i].y_offset(), output_ptr_event->y_offset());
+ EXPECT_EQ(kTestData[i].x_offset_ordinal(),
+ output_ptr_event->x_offset_ordinal());
+ EXPECT_EQ(kTestData[i].y_offset_ordinal(),
+ output_ptr_event->y_offset_ordinal());
+ EXPECT_EQ(kTestData[i].finger_count(), output_ptr_event->finger_count());
+ EXPECT_EQ(kTestData[i].momentum_phase(),
+ output_ptr_event->momentum_phase());
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/events/ozone/device/device_manager.cc b/chromium/ui/events/ozone/device/device_manager.cc
index 59db5c5d94c..7952fcbb7f2 100644
--- a/chromium/ui/events/ozone/device/device_manager.cc
+++ b/chromium/ui/events/ozone/device/device_manager.cc
@@ -4,7 +4,6 @@
#include "ui/events/ozone/device/device_manager.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#if defined(USE_UDEV)
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.cc b/chromium/ui/events/ozone/device/device_manager_manual.cc
index 8010870abd4..9a68ca01742 100644
--- a/chromium/ui/events/ozone/device/device_manager_manual.cc
+++ b/chromium/ui/events/ozone/device/device_manager_manual.cc
@@ -17,11 +17,11 @@ namespace ui {
namespace {
-const char kDevInput[] = "/dev/input";
+const base::FilePath::CharType kDevInput[] = FILE_PATH_LITERAL("/dev/input");
void ScanDevicesOnWorkerThread(std::vector<base::FilePath>* result) {
- base::FileEnumerator file_enum(base::FilePath(FILE_PATH_LITERAL(kDevInput)),
- false, base::FileEnumerator::FILES,
+ base::FileEnumerator file_enum(base::FilePath(kDevInput), false,
+ base::FileEnumerator::FILES,
FILE_PATH_LITERAL("event*[0-9]"));
for (base::FilePath path = file_enum.Next(); !path.empty();
path = file_enum.Next()) {
@@ -58,7 +58,7 @@ void DeviceManagerManual::RemoveObserver(DeviceEventObserver* observer) {
}
void DeviceManagerManual::StartWatching() {
- if (!watcher_.Watch(base::FilePath(FILE_PATH_LITERAL(kDevInput)), false,
+ if (!watcher_.Watch(base::FilePath(kDevInput), false,
base::Bind(&DeviceManagerManual::OnWatcherEvent,
weak_ptr_factory_.GetWeakPtr()))) {
LOG(ERROR) << "Failed to start FilePathWatcher";
@@ -70,9 +70,9 @@ void DeviceManagerManual::InitiateScanDevices() {
base::PostTaskWithTraitsAndReply(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
- base::Bind(&ScanDevicesOnWorkerThread, result),
- base::Bind(&DeviceManagerManual::OnDevicesScanned,
- weak_ptr_factory_.GetWeakPtr(), base::Owned(result)));
+ base::BindOnce(&ScanDevicesOnWorkerThread, result),
+ base::BindOnce(&DeviceManagerManual::OnDevicesScanned,
+ weak_ptr_factory_.GetWeakPtr(), base::Owned(result)));
}
void DeviceManagerManual::OnDevicesScanned(
diff --git a/chromium/ui/events/ozone/device/udev/device_manager_udev.cc b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
index 655285f6fd2..16421005e1e 100644
--- a/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
+++ b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -7,7 +7,6 @@
#include <stddef.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/ui/events/ozone/device/udev/device_manager_udev.h b/chromium/ui/events/ozone/device/udev/device_manager_udev.h
index e7a3425c35c..3e1a6feabac 100644
--- a/chromium/ui/events/ozone/device/udev/device_manager_udev.h
+++ b/chromium/ui/events/ozone/device/udev/device_manager_udev.h
@@ -16,8 +16,8 @@ namespace ui {
class DeviceEvent;
class DeviceEventObserver;
-class DeviceManagerUdev
- : public DeviceManager, base::MessagePumpLibevent::Watcher {
+class DeviceManagerUdev : public DeviceManager,
+ base::MessagePumpLibevent::FdWatcher {
public:
DeviceManagerUdev();
~DeviceManagerUdev() override;
@@ -33,14 +33,14 @@ class DeviceManagerUdev
void AddObserver(DeviceEventObserver* observer) override;
void RemoveObserver(DeviceEventObserver* observer) override;
- // base::MessagePumpLibevent::Watcher overrides:
+ // base::MessagePumpLibevent::FdWatcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
device::ScopedUdevPtr udev_;
device::ScopedUdevMonitorPtr monitor_;
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
base::ObserverList<DeviceEventObserver> observers_;
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/event_converter_evdev.cc
index bf14bd57f40..dc766606cb8 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -24,6 +24,7 @@ EventConverterEvdev::EventConverterEvdev(int fd,
int id,
InputDeviceType type,
const std::string& name,
+ const std::string& phys,
uint16_t vendor_id,
uint16_t product_id)
: fd_(fd),
@@ -31,6 +32,7 @@ EventConverterEvdev::EventConverterEvdev(int fd,
input_device_(id,
type,
name,
+ phys,
GetInputPathInSys(path),
vendor_id,
product_id),
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev.h b/chromium/ui/events/ozone/evdev/event_converter_evdev.h
index 76f63fb0b98..0b786379d0b 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev.h
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev.h
@@ -24,13 +24,14 @@ namespace ui {
enum class DomCode;
class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdev
- : public base::MessagePumpLibevent::Watcher {
+ : public base::MessagePumpLibevent::FdWatcher {
public:
EventConverterEvdev(int fd,
const base::FilePath& path,
int id,
InputDeviceType type,
const std::string& name,
+ const std::string& phys,
uint16_t vendor_id,
uint16_t product_id);
~EventConverterEvdev() override;
@@ -115,7 +116,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdev
static base::TimeTicks TimeTicksFromInputEvent(const input_event& event);
protected:
- // base::MessagePumpLibevent::Watcher:
+ // base::MessagePumpLibevent::FdWatcher:
void OnFileCanWriteWithoutBlocking(int fd) override;
// File descriptor to read.
@@ -132,7 +133,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdev
bool watching_ = false;
// Controller for watching the input fd.
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
private:
DISALLOW_COPY_AND_ASSIGN(EventConverterEvdev);
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 161065a0752..eb8923faf28 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -41,6 +41,7 @@ EventConverterEvdevImpl::EventConverterEvdevImpl(
id,
devinfo.device_type(),
devinfo.name(),
+ devinfo.phys(),
devinfo.vendor_id(),
devinfo.product_id()),
input_device_fd_(std::move(fd)),
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.h b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.h
index c2b5f8e4202..94e4a36a30c 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.h
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -82,7 +82,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdevImpl
int y_offset_ = 0;
// Controller for watching the input fd.
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
// The evdev codes of the keys which should be blocked.
std::bitset<KEY_CNT> blocked_keys_;
diff --git a/chromium/ui/events/ozone/evdev/event_converter_test_util.cc b/chromium/ui/events/ozone/evdev/event_converter_test_util.cc
index 9437c54cd3c..52d339cb8c2 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_test_util.cc
+++ b/chromium/ui/events/ozone/evdev/event_converter_test_util.cc
@@ -6,7 +6,6 @@
#include <stdint.h>
-#include "base/memory/ptr_util.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
@@ -110,8 +109,7 @@ class TestEventFactoryEvdev : public EventFactoryEvdev {
~TestEventFactoryEvdev() override {}
private:
- uint32_t DispatchEvent(PlatformEvent platform_event) override {
- Event* event = static_cast<Event*>(platform_event);
+ uint32_t DispatchEvent(PlatformEvent event) override {
callback_.Run(event);
return POST_DISPATCH_NONE;
}
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.cc b/chromium/ui/events/ozone/evdev/event_device_info.cc
index 09bc96ff19c..c04cf9c51b4 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info.cc
@@ -87,6 +87,15 @@ bool GetDeviceIdentifiers(int fd,
return true;
}
+void GetDevicePhysInfo(int fd, const base::FilePath& path, std::string* phys) {
+ char device_phys[kMaximumDeviceNameLength];
+ if (ioctl(fd, EVIOCGPHYS(kMaximumDeviceNameLength - 1), &device_phys) < 0) {
+ PLOG(INFO) << "Failed EVIOCGPHYS (path=" << path.value() << ")";
+ return;
+ }
+ *phys = device_phys;
+}
+
// |request| needs to be the equivalent to:
// struct input_mt_request_layout {
// uint32_t code;
@@ -184,6 +193,8 @@ bool EventDeviceInfo::Initialize(int fd, const base::FilePath& path) {
if (!GetDeviceIdentifiers(fd, path, &vendor_id_, &product_id_))
return false;
+ GetDevicePhysInfo(fd, path, &phys_);
+
device_type_ = GetInputDeviceTypeFromPath(path);
return true;
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.h b/chromium/ui/events/ozone/evdev/event_device_info.h
index 24b79806751..e7624594c05 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.h
+++ b/chromium/ui/events/ozone/evdev/event_device_info.h
@@ -93,6 +93,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
// Device identification.
const std::string& name() const { return name_; }
+ const std::string& phys() const { return phys_; }
uint16_t vendor_id() const { return vendor_id_; }
uint16_t product_id() const { return product_id_; }
@@ -177,6 +178,10 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
uint16_t vendor_id_;
uint16_t product_id_;
+ // Device evdev physical property containing the output for EVIOCGPHYS that is
+ // (supposed to be) stable between reboots and hotplugs.
+ std::string phys_;
+
// Whether this is an internal or external device.
InputDeviceType device_type_ = InputDeviceType::INPUT_DEVICE_UNKNOWN;
diff --git a/chromium/ui/events/ozone/evdev/event_factory_evdev.cc b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
index 92c84d05be6..2d44b91a0ea 100644
--- a/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -44,97 +43,101 @@ class ProxyDeviceEventDispatcher : public DeviceEventDispatcherEvdev {
// DeviceEventDispatcher:
void DispatchKeyEvent(const KeyEventParams& params) override {
- ui_thread_runner_->PostTask(FROM_HERE,
- base::Bind(&EventFactoryEvdev::DispatchKeyEvent,
- event_factory_evdev_, params));
+ ui_thread_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchKeyEvent,
+ event_factory_evdev_, params));
}
void DispatchMouseMoveEvent(const MouseMoveEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseMoveEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchMouseMoveEvent,
+ event_factory_evdev_, params));
}
void DispatchMouseButtonEvent(const MouseButtonEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseButtonEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchMouseButtonEvent,
+ event_factory_evdev_, params));
}
void DispatchMouseWheelEvent(const MouseWheelEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseWheelEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchMouseWheelEvent,
+ event_factory_evdev_, params));
}
void DispatchPinchEvent(const PinchEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchPinchEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchPinchEvent,
+ event_factory_evdev_, params));
}
void DispatchScrollEvent(const ScrollEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchScrollEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchScrollEvent,
+ event_factory_evdev_, params));
}
void DispatchTouchEvent(const TouchEventParams& params) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchTouchEvent,
- event_factory_evdev_, params));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchTouchEvent,
+ event_factory_evdev_, params));
}
void DispatchGamepadEvent(const GamepadEvent& event) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchGamepadEvent,
- event_factory_evdev_, event));
+ FROM_HERE, base::BindOnce(&EventFactoryEvdev::DispatchGamepadEvent,
+ event_factory_evdev_, event));
}
void DispatchKeyboardDevicesUpdated(
const std::vector<InputDevice>& devices) override {
ui_thread_runner_->PostTask(
FROM_HERE,
- base::Bind(&EventFactoryEvdev::DispatchKeyboardDevicesUpdated,
- event_factory_evdev_, devices));
+ base::BindOnce(&EventFactoryEvdev::DispatchKeyboardDevicesUpdated,
+ event_factory_evdev_, devices));
}
void DispatchTouchscreenDevicesUpdated(
const std::vector<TouchscreenDevice>& devices) override {
ui_thread_runner_->PostTask(
FROM_HERE,
- base::Bind(&EventFactoryEvdev::DispatchTouchscreenDevicesUpdated,
- event_factory_evdev_, devices));
+ base::BindOnce(&EventFactoryEvdev::DispatchTouchscreenDevicesUpdated,
+ event_factory_evdev_, devices));
}
void DispatchMouseDevicesUpdated(
const std::vector<InputDevice>& devices) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchMouseDevicesUpdated,
- event_factory_evdev_, devices));
+ FROM_HERE,
+ base::BindOnce(&EventFactoryEvdev::DispatchMouseDevicesUpdated,
+ event_factory_evdev_, devices));
}
void DispatchTouchpadDevicesUpdated(
const std::vector<InputDevice>& devices) override {
ui_thread_runner_->PostTask(
FROM_HERE,
- base::Bind(&EventFactoryEvdev::DispatchTouchpadDevicesUpdated,
- event_factory_evdev_, devices));
+ base::BindOnce(&EventFactoryEvdev::DispatchTouchpadDevicesUpdated,
+ event_factory_evdev_, devices));
}
void DispatchDeviceListsComplete() override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchDeviceListsComplete,
- event_factory_evdev_));
+ FROM_HERE,
+ base::BindOnce(&EventFactoryEvdev::DispatchDeviceListsComplete,
+ event_factory_evdev_));
}
void DispatchStylusStateChanged(StylusState stylus_state) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchStylusStateChanged,
- event_factory_evdev_, stylus_state));
+ FROM_HERE,
+ base::BindOnce(&EventFactoryEvdev::DispatchStylusStateChanged,
+ event_factory_evdev_, stylus_state));
}
void DispatchGamepadDevicesUpdated(
const std::vector<InputDevice>& devices) override {
ui_thread_runner_->PostTask(
- FROM_HERE, base::Bind(&EventFactoryEvdev::DispatchGamepadDevicesUpdated,
- event_factory_evdev_, devices));
+ FROM_HERE,
+ base::BindOnce(&EventFactoryEvdev::DispatchGamepadDevicesUpdated,
+ event_factory_evdev_, devices));
}
private:
@@ -446,12 +449,12 @@ void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget,
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&EventFactoryEvdev::DispatchMouseMoveEvent,
- weak_ptr_factory_.GetWeakPtr(),
- MouseMoveEventParams(
- -1 /* device_id */, EF_NONE, cursor_->GetLocation(),
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE),
- EventTimeForNow())));
+ base::BindOnce(&EventFactoryEvdev::DispatchMouseMoveEvent,
+ weak_ptr_factory_.GetWeakPtr(),
+ MouseMoveEventParams(
+ -1 /* device_id */, EF_NONE, cursor_->GetLocation(),
+ PointerDetails(EventPointerType::POINTER_TYPE_MOUSE),
+ EventTimeForNow())));
}
int EventFactoryEvdev::NextDeviceId() {
diff --git a/chromium/ui/events/ozone/evdev/event_thread_evdev.cc b/chromium/ui/events/ozone/evdev/event_thread_evdev.cc
index d0dc561aafd..1dcc69740ab 100644
--- a/chromium/ui/events/ozone/evdev/event_thread_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/event_thread_evdev.cc
@@ -48,7 +48,7 @@ class EvdevThread : public base::Thread {
cursor_->InitializeOnEvdev();
init_runner_->PostTask(FROM_HERE,
- base::Bind(init_callback_, base::Passed(&proxy)));
+ base::BindOnce(init_callback_, std::move(proxy)));
}
void CleanUp() override {
diff --git a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
index c1714879a51..3aec220b996 100644
--- a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
@@ -99,6 +99,7 @@ GamepadEventConverterEvdev::GamepadEventConverterEvdev(
id,
devinfo.device_type(),
devinfo.name(),
+ devinfo.phys(),
devinfo.vendor_id(),
devinfo.product_id()),
will_send_frame_(false),
diff --git a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
index d3123c8900f..b768ad655ad 100644
--- a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
@@ -18,7 +18,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
#include "base/time/time.h"
diff --git a/chromium/ui/events/ozone/evdev/input_controller_evdev.cc b/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
index 86a65521954..3834a69b344 100644
--- a/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include "base/callback.h"
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/ozone/evdev/input_device_factory_evdev_proxy.h"
@@ -183,8 +182,8 @@ void InputControllerEvdev::ScheduleUpdateDeviceSettings() {
if (!input_device_factory_ || settings_update_pending_)
return;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&InputControllerEvdev::UpdateDeviceSettings,
- weak_ptr_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&InputControllerEvdev::UpdateDeviceSettings,
+ weak_ptr_factory_.GetWeakPtr()));
settings_update_pending_ = true;
}
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 4cc71e34d38..28e0c5dffb5 100644
--- a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -189,8 +189,8 @@ void InputDeviceFactoryEvdev::AddInputDevice(int id,
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&InputDeviceFactoryEvdev::AttachInputDevice,
- weak_ptr_factory_.GetWeakPtr(), base::Passed(&converter)));
+ base::BindOnce(&InputDeviceFactoryEvdev::AttachInputDevice,
+ weak_ptr_factory_.GetWeakPtr(), std::move(converter)));
++pending_device_changes_;
}
diff --git a/chromium/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc b/chromium/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
index 2696967a0cb..af6a0f7ed92 100644
--- a/chromium/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
+++ b/chromium/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
@@ -43,35 +43,36 @@ InputDeviceFactoryEvdevProxy::~InputDeviceFactoryEvdevProxy() {
void InputDeviceFactoryEvdevProxy::AddInputDevice(int id,
const base::FilePath& path) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&InputDeviceFactoryEvdev::AddInputDevice,
- input_device_factory_, id, path));
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::AddInputDevice,
+ input_device_factory_, id, path));
}
void InputDeviceFactoryEvdevProxy::RemoveInputDevice(
const base::FilePath& path) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&InputDeviceFactoryEvdev::RemoveInputDevice,
- input_device_factory_, path));
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::RemoveInputDevice,
+ input_device_factory_, path));
}
void InputDeviceFactoryEvdevProxy::OnStartupScanComplete() {
task_runner_->PostTask(
- FROM_HERE, base::Bind(&InputDeviceFactoryEvdev::OnStartupScanComplete,
- input_device_factory_));
+ FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::OnStartupScanComplete,
+ input_device_factory_));
}
void InputDeviceFactoryEvdevProxy::SetCapsLockLed(bool enabled) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&InputDeviceFactoryEvdev::SetCapsLockLed,
- input_device_factory_, enabled));
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::SetCapsLockLed,
+ input_device_factory_, enabled));
}
void InputDeviceFactoryEvdevProxy::UpdateInputDeviceSettings(
const InputDeviceSettingsEvdev& settings) {
task_runner_->PostTask(
- FROM_HERE, base::Bind(&InputDeviceFactoryEvdev::UpdateInputDeviceSettings,
- input_device_factory_, settings));
+ FROM_HERE,
+ base::BindOnce(&InputDeviceFactoryEvdev::UpdateInputDeviceSettings,
+ input_device_factory_, settings));
}
void InputDeviceFactoryEvdevProxy::GetTouchDeviceStatus(
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
index 9ec3121dbb0..98c868de9ed 100644
--- a/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -38,6 +38,7 @@ EventReaderLibevdevCros::EventReaderLibevdevCros(
id,
devinfo.device_type(),
devinfo.name(),
+ devinfo.phys(),
devinfo.vendor_id(),
devinfo.product_id()),
has_keyboard_(devinfo.HasKeyboard()),
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 d4f5af789ad..f7597bb4b53 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
@@ -211,6 +211,14 @@ void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev,
hwstate.buttons_down |= GESTURES_BUTTON_FORWARD;
}
+ // Check if this event has an MSC_TIMESTAMP field
+ if (EvdevBitIsSet(evdev->info.msc_bitmask, MSC_TIMESTAMP)) {
+ hwstate.msc_timestamp = static_cast<stime_t>(Event_Get_Timestamp(evdev)) /
+ base::Time::kMicrosecondsPerSecond;
+ } else {
+ hwstate.msc_timestamp = 0.0;
+ }
+
GestureInterpreterPushHardwareState(interpreter_, &hwstate);
}
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 531268241d8..b702ea1dceb 100644
--- a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
@@ -42,6 +42,7 @@ TabletEventConverterEvdev::TabletEventConverterEvdev(
id,
info.device_type(),
info.name(),
+ info.phys(),
info.vendor_id(),
info.product_id()),
input_device_fd_(std::move(fd)),
diff --git a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.h b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.h
index 6d22b98d9db..f6bf158abaf 100644
--- a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.h
+++ b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.h
@@ -53,7 +53,7 @@ class EVENTS_OZONE_EVDEV_EXPORT TabletEventConverterEvdev
base::ScopedFD input_device_fd_;
// Controller for watching the input fd.
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
// Shared cursor state.
CursorDelegateEvdev* cursor_;
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index 7141819c6d4..6818808166c 100644
--- a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -125,6 +125,7 @@ TouchEventConverterEvdev::TouchEventConverterEvdev(
id,
devinfo.device_type(),
devinfo.name(),
+ devinfo.phys(),
devinfo.vendor_id(),
devinfo.product_id()),
input_device_fd_(std::move(fd)),
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h
index 7e5c6c0756e..02022f6ff08 100644
--- a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -68,7 +68,7 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
private:
friend class MockTouchEventConverterEvdev;
- // Overidden from base::MessagePumpLibevent::Watcher.
+ // Overidden from base::MessagePumpLibevent::FdWatcher.
void OnFileCanReadWithoutBlocking(int fd) override;
virtual void Reinitialize();
diff --git a/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder.cc b/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder.cc
index a5d1a483ddd..1b0d7121c12 100644
--- a/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder.cc
+++ b/chromium/ui/events/ozone/evdev/touch_filter/false_touch_finder.cc
@@ -4,7 +4,6 @@
#include "ui/events/ozone/evdev/touch_filter/false_touch_finder.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "ui/events/event_utils.h"
#include "ui/events/ozone/evdev/touch_filter/edge_touch_filter.h"
diff --git a/chromium/ui/events/ozone/events_ozone.cc b/chromium/ui/events/ozone/events_ozone.cc
index 94c0427aba4..a9dae509d19 100644
--- a/chromium/ui/events/ozone/events_ozone.cc
+++ b/chromium/ui/events/ozone/events_ozone.cc
@@ -9,28 +9,31 @@
namespace ui {
void DispatchEventFromNativeUiEvent(
- const base::NativeEvent& native_event,
+ const PlatformEvent& event,
base::OnceCallback<void(ui::Event*)> callback) {
- ui::Event* native_ui_event = static_cast<ui::Event*>(native_event);
- if (native_ui_event->IsKeyEvent()) {
- ui::KeyEvent key_event(native_event);
+ // NB: ui::Events are constructed here using the overload that takes a
+ // const PlatformEvent& (here ui::Event* const&) rather than the copy
+ // constructor. This has side effects and cannot be changed to use the
+ // copy constructor or Event::Clone.
+ if (event->IsKeyEvent()) {
+ ui::KeyEvent key_event(event);
std::move(callback).Run(&key_event);
- } else if (native_ui_event->IsMouseWheelEvent()) {
- ui::MouseWheelEvent wheel_event(native_event);
+ } else if (event->IsMouseWheelEvent()) {
+ ui::MouseWheelEvent wheel_event(event);
std::move(callback).Run(&wheel_event);
- } else if (native_ui_event->IsMouseEvent()) {
- ui::MouseEvent mouse_event(native_event);
+ } else if (event->IsMouseEvent()) {
+ ui::MouseEvent mouse_event(event);
std::move(callback).Run(&mouse_event);
- } else if (native_ui_event->IsTouchEvent()) {
- ui::TouchEvent touch_event(native_event);
+ } else if (event->IsTouchEvent()) {
+ ui::TouchEvent touch_event(event);
std::move(callback).Run(&touch_event);
- } else if (native_ui_event->IsScrollEvent()) {
- ui::ScrollEvent scroll_event(native_event);
+ } else if (event->IsScrollEvent()) {
+ ui::ScrollEvent scroll_event(event);
std::move(callback).Run(&scroll_event);
- } else if (native_ui_event->IsGestureEvent()) {
- std::move(callback).Run(native_ui_event);
+ } else if (event->IsGestureEvent()) {
+ std::move(callback).Run(event);
// TODO(mohsen): Use the same pattern for scroll/touch/wheel events.
- // Apparently, there is no need for them to wrap the |native_event|.
+ // Apparently, there is no need for them to wrap the |event|.
} else {
NOTREACHED();
}
diff --git a/chromium/ui/events/ozone/events_ozone.h b/chromium/ui/events/ozone/events_ozone.h
index 23935f35f1f..6a893e1e42b 100644
--- a/chromium/ui/events/ozone/events_ozone.h
+++ b/chromium/ui/events/ozone/events_ozone.h
@@ -6,8 +6,8 @@
#define UI_EVENTS_OZONE_EVENTS_OZONE_H_
#include "base/callback.h"
-#include "base/event_types.h"
#include "ui/events/events_export.h"
+#include "ui/events/platform_event.h"
namespace ui {
@@ -31,7 +31,7 @@ class Event;
// define NativeEvent == ui::Event.
//
EVENTS_EXPORT void DispatchEventFromNativeUiEvent(
- const base::NativeEvent& native_event,
+ const PlatformEvent& native_event,
base::OnceCallback<void(ui::Event*)> callback);
} // namespace ui
diff --git a/chromium/ui/events/ozone/gamepad/gamepad_mapping.cc b/chromium/ui/events/ozone/gamepad/gamepad_mapping.cc
index 6e1d96cb331..26c6b73c5f4 100644
--- a/chromium/ui/events/ozone/gamepad/gamepad_mapping.cc
+++ b/chromium/ui/events/ozone/gamepad/gamepad_mapping.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/gamepad/generic_gamepad_mapping.h"
#include "ui/events/ozone/gamepad/static_gamepad_mapping.h"
diff --git a/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping.cc b/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping.cc
index 3b0ef4d3557..d18ff455bfc 100644
--- a/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping.cc
+++ b/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping.cc
@@ -11,7 +11,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/gamepad/generic_gamepad_mapping.h"
#include "ui/events/ozone/gamepad/webgamepad_constants.h"
diff --git a/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc b/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc
index 7ac37b4d623..2f40517f93a 100644
--- a/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc
+++ b/chromium/ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc
@@ -17,7 +17,6 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
#include "base/time/time.h"
diff --git a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
index fb89349e6dc..0830460bc98 100644
--- a/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
+++ b/chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
@@ -8,7 +8,6 @@
#include <stdint.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
diff --git a/chromium/ui/events/platform/BUILD.gn b/chromium/ui/events/platform/BUILD.gn
index 5055e6c0688..dfceb31d1de 100644
--- a/chromium/ui/events/platform/BUILD.gn
+++ b/chromium/ui/events/platform/BUILD.gn
@@ -15,7 +15,6 @@ jumbo_component("platform") {
"platform_event_source.cc",
"platform_event_source.h",
"platform_event_source_stub.cc",
- "platform_event_types.h",
"scoped_event_dispatcher.cc",
"scoped_event_dispatcher.h",
]
@@ -24,6 +23,7 @@ jumbo_component("platform") {
deps = [
"//base",
+ "//ui/events:platform_event",
]
if (use_x11) {
diff --git a/chromium/ui/events/platform/platform_event_dispatcher.h b/chromium/ui/events/platform/platform_event_dispatcher.h
index 294bdb9a691..d54c5101acd 100644
--- a/chromium/ui/events/platform/platform_event_dispatcher.h
+++ b/chromium/ui/events/platform/platform_event_dispatcher.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "ui/events/events_export.h"
-#include "ui/events/platform/platform_event_types.h"
+#include "ui/events/platform_event.h"
namespace ui {
diff --git a/chromium/ui/events/platform/platform_event_observer.h b/chromium/ui/events/platform/platform_event_observer.h
index 37aec638ea5..3b1cc9e4e64 100644
--- a/chromium/ui/events/platform/platform_event_observer.h
+++ b/chromium/ui/events/platform/platform_event_observer.h
@@ -6,7 +6,7 @@
#define UI_EVENTS_PLATFORM_PLATFORM_EVENT_OBSERVER_H_
#include "ui/events/events_export.h"
-#include "ui/events/platform/platform_event_types.h"
+#include "ui/events/platform_event.h"
namespace ui {
diff --git a/chromium/ui/events/platform/platform_event_source.cc b/chromium/ui/events/platform/platform_event_source.cc
index 9e8324389f7..cdd9ce7319d 100644
--- a/chromium/ui/events/platform/platform_event_source.cc
+++ b/chromium/ui/events/platform/platform_event_source.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/lazy_instance.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_local.h"
#include "ui/events/platform/platform_event_dispatcher.h"
diff --git a/chromium/ui/events/platform/platform_event_source.h b/chromium/ui/events/platform/platform_event_source.h
index b4e3084dd1f..dae150479b1 100644
--- a/chromium/ui/events/platform/platform_event_source.h
+++ b/chromium/ui/events/platform/platform_event_source.h
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/events/events_export.h"
-#include "ui/events/platform/platform_event_types.h"
+#include "ui/events/platform_event.h"
namespace ui {
@@ -78,6 +78,8 @@ class EVENTS_EXPORT PlatformEventSource {
// current message-loop iteration.
virtual uint32_t DispatchEvent(PlatformEvent platform_event);
+ base::ObserverList<PlatformEventObserver>& observers() { return observers_; }
+
private:
friend class ScopedEventDispatcher;
friend class test::PlatformEventSourceTestAPI;
diff --git a/chromium/ui/events/platform/platform_event_source_unittest.cc b/chromium/ui/events/platform/platform_event_source_unittest.cc
index ccaa3681499..d9a069e42cb 100644
--- a/chromium/ui/events/platform/platform_event_source_unittest.cc
+++ b/chromium/ui/events/platform/platform_event_source_unittest.cc
@@ -13,10 +13,10 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/platform/platform_event_observer.h"
@@ -499,8 +499,9 @@ class PlatformEventTestWithMessageLoop : public PlatformEventTest {
void Run() {
message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&PlatformEventTestWithMessageLoop::RunTestImpl,
- base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&PlatformEventTestWithMessageLoop::RunTestImpl,
+ base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
@@ -646,11 +647,9 @@ class DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration
list.clear();
overriding.SetScopedHandle(std::move(override_handle));
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
+ base::BindOnce(
&DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration::
NestedTask,
base::Unretained(this), base::Unretained(&list),
@@ -665,7 +664,7 @@ class DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration
}
private:
- base::RunLoop run_loop_;
+ base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
};
RUN_TEST_IN_MESSAGE_LOOP(
@@ -709,14 +708,12 @@ class ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration
second_overriding.SetScopedHandle(std::move(second_override_handle));
second_overriding.set_post_dispatch_action(POST_DISPATCH_NONE);
- base::RunLoop run_loop;
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
second_overriding.set_callback(run_loop.QuitClosure());
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(base::IgnoreResult(&TestPlatformEventSource::Dispatch),
- base::Unretained(source()), *event));
+ base::BindOnce(base::IgnoreResult(&TestPlatformEventSource::Dispatch),
+ base::Unretained(source()), *event));
run_loop.Run();
ASSERT_EQ(2u, list->size());
EXPECT_EQ(15, (*list)[0]);
@@ -748,14 +745,12 @@ class ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration
// Start a nested message-loop, and destroy |override_handle| in the nested
// loop. That should terminate the nested loop, restore the previous
// dispatchers, and return control to this function.
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
- loop->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
+ base::BindOnce(
&ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration::
NestedTask,
- base::Unretained(this), base::Passed(&override_handle),
+ base::Unretained(this), std::move(override_handle),
base::Unretained(&list)));
run_loop_.Run();
@@ -767,7 +762,7 @@ class ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration
}
private:
- base::RunLoop run_loop_;
+ base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
};
RUN_TEST_IN_MESSAGE_LOOP(
diff --git a/chromium/ui/events/platform/platform_event_types.h b/chromium/ui/events/platform/platform_event_types.h
deleted file mode 100644
index dedb38ff063..00000000000
--- a/chromium/ui/events/platform/platform_event_types.h
+++ /dev/null
@@ -1,14 +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_EVENTS_PLATFORM_PLATFORM_EVENT_TYPES_H_
-#define UI_EVENTS_PLATFORM_PLATFORM_EVENT_TYPES_H_
-
-#include "base/event_types.h"
-
-namespace ui {
-typedef base::NativeEvent PlatformEvent;
-} // namespace ui
-
-#endif // UI_EVENTS_PLATFORM_PLATFORM_EVENT_TYPES_H_
diff --git a/chromium/ui/events/platform/x11/BUILD.gn b/chromium/ui/events/platform/x11/BUILD.gn
index d4c7462d4db..31a20f03e55 100644
--- a/chromium/ui/events/platform/x11/BUILD.gn
+++ b/chromium/ui/events/platform/x11/BUILD.gn
@@ -38,6 +38,10 @@ jumbo_component("x11") {
"//base",
]
+ if (is_chromeos) {
+ deps += [ "//ui/events/ozone:events_ozone" ]
+ }
+
if (use_glib) {
sources += [
"x11_event_source_glib.cc",
diff --git a/chromium/ui/events/platform/x11/x11_event_source.cc b/chromium/ui/events/platform/x11/x11_event_source.cc
index ed3581a9c2b..897248a214a 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.cc
+++ b/chromium/ui/events/platform/x11/x11_event_source.cc
@@ -183,6 +183,7 @@ Time X11EventSource::GetTimestamp() {
return GetCurrentServerTime();
}
+#if !defined(USE_OZONE)
base::Optional<gfx::Point>
X11EventSource::GetRootCursorLocationFromCurrentEvent() const {
if (!dispatching_event_)
@@ -218,6 +219,7 @@ X11EventSource::GetRootCursorLocationFromCurrentEvent() const {
return ui::EventSystemLocationFromNative(event);
return base::nullopt;
}
+#endif
////////////////////////////////////////////////////////////////////////////////
// X11EventSource, protected
diff --git a/chromium/ui/events/platform/x11/x11_event_source.h b/chromium/ui/events/platform/x11/x11_event_source.h
index a0cd370181c..1df54b42367 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.h
+++ b/chromium/ui/events/platform/x11/x11_event_source.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/optional.h"
+#include "build/build_config.h"
#include "ui/events/events_export.h"
#include "ui/gfx/x/x11_types.h"
@@ -69,9 +70,11 @@ class EVENTS_EXPORT X11EventSource {
// current event does not have a timestamp.
Time GetTimestamp();
+#if !defined(USE_OZONE)
// Returns the root pointer location only if there is an event being
// dispatched that contains that information.
base::Optional<gfx::Point> GetRootCursorLocationFromCurrentEvent() const;
+#endif
void StopCurrentEventStream();
void OnDispatcherListChanged();
diff --git a/chromium/ui/events/platform/x11/x11_event_source_glib.cc b/chromium/ui/events/platform/x11/x11_event_source_glib.cc
index b5af868de64..e82e4c652be 100644
--- a/chromium/ui/events/platform/x11/x11_event_source_glib.cc
+++ b/chromium/ui/events/platform/x11/x11_event_source_glib.cc
@@ -7,7 +7,6 @@
#include <glib.h>
#include "ui/gfx/x/x11.h"
-#include "base/memory/ptr_util.h"
namespace ui {
diff --git a/chromium/ui/events/platform/x11/x11_event_source_libevent.cc b/chromium/ui/events/platform/x11/x11_event_source_libevent.cc
index e5831579836..63826141757 100644
--- a/chromium/ui/events/platform/x11/x11_event_source_libevent.cc
+++ b/chromium/ui/events/platform/x11/x11_event_source_libevent.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
@@ -15,6 +14,10 @@
#include "ui/events/x/events_x_utils.h"
#include "ui/gfx/x/x11.h"
+#if defined(OS_CHROMEOS)
+#include "ui/events/ozone/chromeos/cursor_controller.h"
+#endif
+
namespace ui {
namespace {
@@ -177,6 +180,12 @@ void X11EventSourceLibevent::RemoveXEventDispatcher(
void X11EventSourceLibevent::ProcessXEvent(XEvent* xevent) {
std::unique_ptr<ui::Event> translated_event = TranslateXEventToEvent(*xevent);
if (translated_event) {
+#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
diff --git a/chromium/ui/events/platform/x11/x11_event_source_libevent.h b/chromium/ui/events/platform/x11/x11_event_source_libevent.h
index 6959e0235e9..b193db0d137 100644
--- a/chromium/ui/events/platform/x11/x11_event_source_libevent.h
+++ b/chromium/ui/events/platform/x11/x11_event_source_libevent.h
@@ -51,7 +51,7 @@ class EVENTS_EXPORT XEventDispatcher {
class EVENTS_EXPORT X11EventSourceLibevent
: public X11EventSourceDelegate,
public PlatformEventSource,
- public base::MessagePumpLibevent::Watcher {
+ public base::MessagePumpLibevent::FdWatcher {
public:
explicit X11EventSourceLibevent(XDisplay* display);
~X11EventSourceLibevent() override;
@@ -94,7 +94,7 @@ class EVENTS_EXPORT X11EventSourceLibevent
void StopCurrentEventStream() override;
void OnDispatcherListChanged() override;
- // base::MessagePumpLibevent::Watcher:
+ // base::MessagePumpLibevent::FdWatcher:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
@@ -103,7 +103,7 @@ class EVENTS_EXPORT X11EventSourceLibevent
// Keep track of all XEventDispatcher to send XEvents directly to.
base::ObserverList<XEventDispatcher> dispatchers_xevent_;
- base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_;
+ base::MessagePumpLibevent::FdWatchController watcher_controller_;
bool initialized_ = false;
DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent);
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 077f181f82c..4686c60bda0 100644
--- a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
+++ b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -108,13 +108,9 @@ struct TouchClassInfo {
struct DeviceInfo {
DeviceInfo(const XIDeviceInfo& device,
DeviceType type,
- const base::FilePath& path,
- uint16_t vendor,
- uint16_t product)
+ const base::FilePath& path)
: id(device.deviceid),
name(device.name),
- vendor_id(vendor),
- product_id(product),
use(device.use),
type(type),
path(path) {
@@ -143,10 +139,6 @@ struct DeviceInfo {
// Internal device name.
std::string name;
- // USB-style device identifiers.
- uint16_t vendor_id;
- uint16_t product_id;
-
// Device type (ie: XIMasterPointer)
int use;
@@ -248,7 +240,7 @@ void HandleKeyboardDevicesInWorker(
devices.push_back(keyboard);
}
- reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+ reply_runner->PostTask(FROM_HERE, base::BindOnce(callback, devices));
}
// Helper used to parse mouse information. When it is done it uses
@@ -267,7 +259,7 @@ void HandleMouseDevicesInWorker(const std::vector<DeviceInfo>& device_infos,
devices.push_back(InputDevice(device_info.id, type, device_info.name));
}
- reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+ reply_runner->PostTask(FROM_HERE, base::BindOnce(callback, devices));
}
// Helper used to parse touchpad information. When it is done it uses
@@ -286,7 +278,7 @@ void HandleTouchpadDevicesInWorker(const std::vector<DeviceInfo>& device_infos,
devices.push_back(InputDevice(device_info.id, type, device_info.name));
}
- reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+ reply_runner->PostTask(FROM_HERE, base::BindOnce(callback, devices));
}
// Helper used to parse touchscreen information. When it is done it uses
@@ -345,7 +337,7 @@ void HandleTouchscreenDevicesInWorker(
}
}
- reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+ reply_runner->PostTask(FROM_HERE, base::BindOnce(callback, devices));
}
// Called on a worker thread to parse the device information.
@@ -433,31 +425,8 @@ void X11HotplugEventHandler::OnHotplugEvent() {
(device.deviceid >= 0 && device.deviceid < kMaxDeviceNum)
? device_types[device.deviceid]
: DEVICE_TYPE_OTHER;
-
- // Obtain the USB-style vendor and product identifiers.
- // (On Linux, XI2 makes this available for all evdev devices.
- uint32_t* product_info;
- Atom type;
- int format_return;
- unsigned long num_items_return;
- unsigned long bytes_after_return;
- uint16_t vendor = 0;
- uint16_t product = 0;
- if (XIGetProperty(gfx::GetXDisplay(), device.deviceid,
- gfx::GetAtom(XI_PROP_PRODUCT_ID), 0, 2, 0, XA_INTEGER,
- &type, &format_return, &num_items_return,
- &bytes_after_return,
- reinterpret_cast<unsigned char**>(&product_info)) == 0 &&
- product_info) {
- if (num_items_return == 2) {
- vendor = product_info[0];
- product = product_info[1];
- }
- XFree(product_info);
- }
-
- device_infos.push_back(DeviceInfo(
- device, device_type, GetDevicePath(display, device), vendor, product));
+ device_infos.push_back(
+ DeviceInfo(device, device_type, GetDevicePath(display, device)));
}
// X11 is not thread safe, so first get all the required state.
diff --git a/chromium/ui/events/platform_event.h b/chromium/ui/events/platform_event.h
new file mode 100644
index 00000000000..817f4310fb3
--- /dev/null
+++ b/chromium/ui/events/platform_event.h
@@ -0,0 +1,43 @@
+// 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_EVENTS_PLATFORM_EVENT_H_
+#define UI_EVENTS_PLATFORM_EVENT_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(USE_X11)
+typedef union _XEvent XEvent;
+#elif defined(OS_MACOSX)
+#if defined(__OBJC__)
+@class NSEvent;
+#else // __OBJC__
+class NSEvent;
+#endif // __OBJC__
+#endif
+
+namespace ui {
+class Event;
+}
+
+namespace ui {
+
+// Cross platform typedefs for native event types.
+#if defined(OS_WIN)
+using PlatformEvent = MSG;
+#elif defined(USE_X11)
+using PlatformEvent = XEvent*;
+#elif defined(OS_MACOSX)
+using PlatformEvent = NSEvent*;
+#elif defined(USE_OZONE)
+using PlatformEvent = ui::Event*;
+#else
+using PlatformEvent = void*;
+#endif
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_EVENT_H_
diff --git a/chromium/ui/events/system_input_injector.cc b/chromium/ui/events/system_input_injector.cc
index 3d9207dd432..bbeb84dccbf 100644
--- a/chromium/ui/events/system_input_injector.cc
+++ b/chromium/ui/events/system_input_injector.cc
@@ -4,7 +4,6 @@
#include "ui/events/system_input_injector.h"
-#include "base/memory/ptr_util.h"
namespace ui {
diff --git a/chromium/ui/events/win/events_win.cc b/chromium/ui/events/win/events_win.cc
index 543741d6081..d7ee6f0c0e7 100644
--- a/chromium/ui/events/win/events_win.cc
+++ b/chromium/ui/events/win/events_win.cc
@@ -28,7 +28,7 @@ namespace {
#define SIGNATURE_MASK 0xFFFFFF00
// Get the native mouse key state from the native event message type.
-int GetNativeMouseKey(const base::NativeEvent& native_event) {
+int GetNativeMouseKey(const PlatformEvent& native_event) {
switch (native_event.message) {
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
@@ -62,36 +62,36 @@ int GetNativeMouseKey(const base::NativeEvent& native_event) {
return 0;
}
-bool IsButtonDown(const base::NativeEvent& native_event) {
+bool IsButtonDown(const PlatformEvent& native_event) {
return ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2) &
native_event.wParam) != 0;
}
-bool IsClientMouseEvent(const base::NativeEvent& native_event) {
+bool IsClientMouseEvent(const PlatformEvent& native_event) {
return native_event.message == WM_MOUSELEAVE ||
native_event.message == WM_MOUSEHOVER ||
(native_event.message >= WM_MOUSEFIRST &&
native_event.message <= WM_MOUSELAST);
}
-bool IsNonClientMouseEvent(const base::NativeEvent& native_event) {
+bool IsNonClientMouseEvent(const PlatformEvent& native_event) {
return native_event.message == WM_NCMOUSELEAVE ||
native_event.message == WM_NCMOUSEHOVER ||
(native_event.message >= WM_NCMOUSEMOVE &&
native_event.message <= WM_NCXBUTTONDBLCLK);
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
+bool IsMouseEvent(const PlatformEvent& native_event) {
return IsClientMouseEvent(native_event) ||
IsNonClientMouseEvent(native_event);
}
-bool IsMouseWheelEvent(const base::NativeEvent& native_event) {
+bool IsMouseWheelEvent(const PlatformEvent& native_event) {
return native_event.message == WM_MOUSEWHEEL ||
native_event.message == WM_MOUSEHWHEEL;
}
-bool IsKeyEvent(const base::NativeEvent& native_event) {
+bool IsKeyEvent(const PlatformEvent& native_event) {
return native_event.message == WM_KEYDOWN ||
native_event.message == WM_SYSKEYDOWN ||
native_event.message == WM_CHAR ||
@@ -100,14 +100,14 @@ bool IsKeyEvent(const base::NativeEvent& native_event) {
native_event.message == WM_SYSKEYUP;
}
-bool IsScrollEvent(const base::NativeEvent& native_event) {
+bool IsScrollEvent(const PlatformEvent& native_event) {
return native_event.message == WM_VSCROLL ||
native_event.message == WM_HSCROLL;
}
// Returns a mask corresponding to the set of pressed modifier keys.
// Checks the current global state and the state sent by client mouse messages.
-int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
+int KeyStateFlagsFromNative(const PlatformEvent& native_event) {
int flags = GetModifiersFromKeyState();
// Check key messages for the extended key flag.
@@ -126,7 +126,7 @@ int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
// Returns a mask corresponding to the set of pressed mouse buttons.
// This includes the button of the given message, even if it is being released.
-int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
+int MouseStateFlagsFromNative(const PlatformEvent& native_event) {
int win_flags = GetNativeMouseKey(native_event);
// Client mouse messages provide key states in their WPARAMs.
@@ -143,7 +143,7 @@ int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
} // namespace
-EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
switch (native_event.message) {
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
@@ -208,7 +208,7 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
return ET_UNKNOWN;
}
-int EventFlagsFromNative(const base::NativeEvent& native_event) {
+int EventFlagsFromNative(const PlatformEvent& native_event) {
int flags = KeyStateFlagsFromNative(native_event);
if (IsMouseEvent(native_event))
flags |= MouseStateFlagsFromNative(native_event);
@@ -216,7 +216,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
return flags;
}
-base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
// On Windows, the native input event timestamp (|native_event.time|) is
// coming from |GetTickCount()| clock [1], while in platform independent code
// path we get timestamps by calling |TimeTicks::Now()|, which, if using high-
@@ -230,7 +230,7 @@ base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
return EventTimeForNow();
}
-gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
POINT native_point;
if ((native_event.message == WM_MOUSELEAVE ||
native_event.message == WM_NCMOUSELEAVE) ||
@@ -256,8 +256,7 @@ gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
return gfx::PointF(gfx::Point(native_point));
}
-gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event) {
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
POINT global_point = {GET_X_LPARAM(native_event.lParam),
GET_Y_LPARAM(native_event.lParam)};
// Wheel events have position in screen coordinates.
@@ -266,21 +265,20 @@ gfx::Point EventSystemLocationFromNative(
return gfx::Point(global_point);
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
return KeyboardCodeForWindowsKeyCode(static_cast<WORD>(native_event.wParam));
}
-DomCode CodeFromNative(const base::NativeEvent& native_event) {
+DomCode CodeFromNative(const PlatformEvent& native_event) {
const uint16_t scan_code = GetScanCodeFromLParam(native_event.lParam);
return CodeForWindowsScanCode(scan_code);
}
-bool IsCharFromNative(const base::NativeEvent& native_event) {
+bool IsCharFromNative(const PlatformEvent& native_event) {
return native_event.message == WM_CHAR || native_event.message == WM_SYSCHAR;
}
-int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event) {
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
switch (GetNativeMouseKey(native_event)) {
case MK_LBUTTON:
return EF_LEFT_MOUSE_BUTTON;
@@ -296,7 +294,7 @@ int GetChangedMouseButtonFlagsFromNative(
}
PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
// We should filter out all the mouse events Synthesized from touch events.
// TODO(lanwei): Will set the pointer ID, see https://crbug.com/616771.
if ((GetMessageExtraInfo() & SIGNATURE_MASK) != MOUSEEVENTF_FROMTOUCHPEN)
@@ -305,7 +303,7 @@ PointerDetails GetMousePointerDetailsFromNative(
return PointerDetails(EventPointerType::POINTER_TYPE_PEN);
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& native_event) {
DCHECK(native_event.message == WM_MOUSEWHEEL ||
native_event.message == WM_MOUSEHWHEEL);
if (native_event.message == WM_MOUSEWHEEL)
@@ -313,24 +311,23 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event.wParam), 0);
}
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+PlatformEvent CopyNativeEvent(const PlatformEvent& event) {
return event;
}
-void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
-}
+void ReleaseCopiedNativeEvent(const PlatformEvent& event) {}
-void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
+void ClearTouchIdIfReleased(const PlatformEvent& xev) {
NOTIMPLEMENTED();
}
-int GetTouchId(const base::NativeEvent& xev) {
+int GetTouchId(const PlatformEvent& xev) {
NOTIMPLEMENTED();
return 0;
}
PointerDetails GetTouchPointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
NOTIMPLEMENTED();
return PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
/* pointer_id*/ 0,
@@ -339,7 +336,7 @@ PointerDetails GetTouchPointerDetailsFromNative(
/* force */ 0.f);
}
-bool GetScrollOffsets(const base::NativeEvent& native_event,
+bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -353,7 +350,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
return false;
}
-bool GetFlingData(const base::NativeEvent& native_event,
+bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
diff --git a/chromium/ui/events/win/keyboard_hook_win.cc b/chromium/ui/events/win/keyboard_hook_win.cc
index 8f92cd5ec72..bc7048ba656 100644
--- a/chromium/ui/events/win/keyboard_hook_win.cc
+++ b/chromium/ui/events/win/keyboard_hook_win.cc
@@ -102,7 +102,7 @@ LRESULT CALLBACK KeyboardHookWin::ProcessKeyEvent(int code,
KBDLLHOOKSTRUCT* ll_hooks = reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param);
if (!IsOSReservedKey(ll_hooks->vkCode) &&
- instance_->ShouldCaptureKeyEvent(ll_hooks->vkCode)) {
+ instance_->ShouldCaptureKeyEvent(ll_hooks->scanCode)) {
MSG msg = {nullptr, w_param, ll_hooks->vkCode,
(ll_hooks->scanCode << 16) | (ll_hooks->flags & 0xFFFF),
ll_hooks->time};
diff --git a/chromium/ui/events/x/events_x.cc b/chromium/ui/events/x/events_x.cc
index 4a22e65a872..b8df7b02091 100644
--- a/chromium/ui/events/x/events_x.cc
+++ b/chromium/ui/events/x/events_x.cc
@@ -72,60 +72,58 @@ unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
namespace ui {
-EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
return EventTypeFromXEvent(*native_event);
}
-int EventFlagsFromNative(const base::NativeEvent& native_event) {
+int EventFlagsFromNative(const PlatformEvent& native_event) {
return EventFlagsFromXEvent(*native_event);
}
-base::TimeTicks EventTimeFromNative(const base::NativeEvent& native_event) {
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
base::TimeTicks timestamp = EventTimeFromXEvent(*native_event);
ValidateEventTimeClock(&timestamp);
return timestamp;
}
-gfx::PointF EventLocationFromNative(const base::NativeEvent& native_event) {
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
return gfx::PointF(EventLocationFromXEvent(*native_event));
}
-gfx::Point EventSystemLocationFromNative(
- const base::NativeEvent& native_event) {
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
return EventSystemLocationFromXEvent(*native_event);
}
-int EventButtonFromNative(const base::NativeEvent& native_event) {
+int EventButtonFromNative(const PlatformEvent& native_event) {
return EventButtonFromXEvent(*native_event);
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
return KeyboardCodeFromXKeyEvent(native_event);
}
-DomCode CodeFromNative(const base::NativeEvent& native_event) {
+DomCode CodeFromNative(const PlatformEvent& native_event) {
return CodeFromXEvent(native_event);
}
-bool IsCharFromNative(const base::NativeEvent& native_event) {
+bool IsCharFromNative(const PlatformEvent& native_event) {
return false;
}
-int GetChangedMouseButtonFlagsFromNative(
- const base::NativeEvent& native_event) {
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
return GetChangedMouseButtonFlagsFromXEvent(*native_event);
}
PointerDetails GetMousePointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
return PointerDetails(EventPointerType::POINTER_TYPE_MOUSE);
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& native_event) {
return GetMouseWheelOffsetFromXEvent(*native_event);
}
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& native_event) {
+PlatformEvent CopyNativeEvent(const PlatformEvent& native_event) {
if (!native_event || native_event->type == GenericEvent)
return NULL;
XEvent* copy = new XEvent;
@@ -133,20 +131,20 @@ base::NativeEvent CopyNativeEvent(const base::NativeEvent& native_event) {
return copy;
}
-void ReleaseCopiedNativeEvent(const base::NativeEvent& native_event) {
+void ReleaseCopiedNativeEvent(const PlatformEvent& native_event) {
delete native_event;
}
-void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
+void ClearTouchIdIfReleased(const PlatformEvent& native_event) {
ClearTouchIdIfReleasedFromXEvent(*native_event);
}
-int GetTouchId(const base::NativeEvent& native_event) {
+int GetTouchId(const PlatformEvent& native_event) {
return GetTouchIdFromXEvent(*native_event);
}
PointerDetails GetTouchPointerDetailsFromNative(
- const base::NativeEvent& native_event) {
+ const PlatformEvent& native_event) {
return PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
GetTouchIdFromXEvent(*native_event),
GetTouchRadiusXFromXEvent(*native_event),
@@ -155,7 +153,7 @@ PointerDetails GetTouchPointerDetailsFromNative(
GetTouchAngleFromXEvent(*native_event));
}
-bool GetScrollOffsets(const base::NativeEvent& native_event,
+bool GetScrollOffsets(const PlatformEvent& native_event,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
@@ -167,7 +165,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
finger_count);
}
-bool GetFlingData(const base::NativeEvent& native_event,
+bool GetFlingData(const PlatformEvent& native_event,
float* vx,
float* vy,
float* vx_ordinal,
diff --git a/chromium/ui/events/x/events_x_unittest.cc b/chromium/ui/events/x/events_x_unittest.cc
index 0022b7f180f..4ca7049243c 100644
--- a/chromium/ui/events/x/events_x_unittest.cc
+++ b/chromium/ui/events/x/events_x_unittest.cc
@@ -11,7 +11,6 @@
#include <utility>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/test/simple_test_tick_clock.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -382,7 +381,7 @@ TEST_F(EventsXTest, TouchEventNotRemovingFromNativeMapping) {
// Copied events should not remove native touch id mappings, as this causes a
// crash (crbug.com/467102). Copied events do not contain a proper
-// base::NativeEvent and should not attempt to access it.
+// PlatformEvent and should not attempt to access it.
TEST_F(EventsXTest, CopiedTouchEventNotRemovingFromNativeMapping) {
std::vector<int> devices;
devices.push_back(0);
diff --git a/chromium/ui/file_manager/file_manager/background/js/compiled_resources2.gyp b/chromium/ui/file_manager/file_manager/background/js/compiled_resources2.gyp
index 171eff0feb0..28942957372 100644
--- a/chromium/ui/file_manager/file_manager/background/js/compiled_resources2.gyp
+++ b/chromium/ui/file_manager/file_manager/background/js/compiled_resources2.gyp
@@ -209,10 +209,20 @@
# 'target_name': 'mock_progress_center',
# 'includes': ['../../../compile_js2.gypi'],
# },
-# {
-# 'target_name': 'mock_volume_manager',
-# 'includes': ['../../../compile_js2.gypi'],
-# },
+ {
+ 'target_name': 'mock_volume_manager',
+ 'dependencies': [
+ '../../../externs/compiled_resources2.gyp:entry_location',
+ '../../../externs/compiled_resources2.gyp:volume_info_list',
+ '../../../externs/compiled_resources2.gyp:volume_info',
+ '../../../externs/compiled_resources2.gyp:volume_manager',
+ '../../common/js/compiled_resources2.gyp:mock_entry',
+ 'volume_info_impl',
+ 'volume_info_list_impl',
+ 'volume_manager_factory',
+ ],
+ 'includes': ['../../../compile_js2.gypi'],
+ },
{
'target_name': 'progress_center',
'dependencies': [
diff --git a/chromium/ui/file_manager/file_manager/common/js/compiled_resources2.gyp b/chromium/ui/file_manager/file_manager/common/js/compiled_resources2.gyp
index a539058b7e8..370faaf31f3 100644
--- a/chromium/ui/file_manager/file_manager/common/js/compiled_resources2.gyp
+++ b/chromium/ui/file_manager/file_manager/common/js/compiled_resources2.gyp
@@ -59,6 +59,14 @@
'includes': ['../../../compile_js2.gypi'],
},
{
+ 'target_name': 'mock_entry',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ 'util',
+ ],
+ 'includes': ['../../../compile_js2.gypi'],
+ },
+ {
'target_name': 'progress_center_common',
'includes': ['../../../compile_js2.gypi'],
},
diff --git a/chromium/ui/file_manager/file_manager/foreground/js/ui/compiled_resources2.gyp b/chromium/ui/file_manager/file_manager/foreground/js/ui/compiled_resources2.gyp
index 039fe8c86f3..645b490d7c6 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/ui/compiled_resources2.gyp
+++ b/chromium/ui/file_manager/file_manager/foreground/js/ui/compiled_resources2.gyp
@@ -268,6 +268,7 @@
'dependencies': [
'../../../../externs/compiled_resources2.gyp:platform',
'../../../../externs/compiled_resources2.gyp:volume_manager',
+ '../../../common/js/compiled_resources2.gyp:metrics',
'../../../common/js/compiled_resources2.gyp:util',
'../../../common/js/compiled_resources2.gyp:volume_manager_common',
'../compiled_resources2.gyp:volume_manager_wrapper',
@@ -309,6 +310,7 @@
'dependencies': [
'../../../../externs/compiled_resources2.gyp:search_item',
'../../../common/js/compiled_resources2.gyp:file_type',
+ '../../../common/js/compiled_resources2.gyp:metrics',
'../../../common/js/compiled_resources2.gyp:util',
'../../elements/compiled_resources2.gyp:files_toggle_ripple',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
diff --git a/chromium/ui/file_manager/file_manager/test/BUILD.gn b/chromium/ui/file_manager/file_manager/test/BUILD.gn
new file mode 100644
index 00000000000..d37ac91f365
--- /dev/null
+++ b/chromium/ui/file_manager/file_manager/test/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+action("create_test_main") {
+ script = "//ui/file_manager/file_manager/test/scripts/create_test_main.py"
+ output = "$target_gen_dir/../test.html"
+ deps = ["//ui/file_manager:resources"]
+ args = [ "--output=" + rebase_path(output, root_build_dir) ]
+ outputs = [
+ output,
+ ]
+}
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
index 9c38caf3ba8..f99576cf60f 100644
--- a/chromium/ui/gfx/BUILD.gn
+++ b/chromium/ui/gfx/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
-import("//device/vr/features/features.gni")
+import("//device/vr/buildflags/buildflags.gni")
import("//testing/test.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
@@ -59,6 +59,8 @@ jumbo_component("gfx") {
"color_utils.h",
"decorated_text.cc",
"decorated_text.h",
+ "decorated_text_mac.h",
+ "decorated_text_mac.mm",
"favicon_size.cc",
"favicon_size.h",
"font.cc",
@@ -123,6 +125,7 @@ jumbo_component("gfx") {
"mac/nswindow_frame_controls.h",
"mac/nswindow_frame_controls.mm",
"mac/scoped_cocoa_disable_screen_updates.h",
+ "mac/scoped_cocoa_disable_screen_updates.mm",
"nine_image_painter.cc",
"nine_image_painter.h",
"path.cc",
@@ -250,7 +253,7 @@ jumbo_component("gfx") {
"//base:base_static",
"//base:i18n",
"//base/third_party/dynamic_annotations",
- "//device/vr/features",
+ "//device/vr/buildflags",
"//skia",
"//third_party/zlib",
]
@@ -601,8 +604,6 @@ static_library("test_support") {
"image/image_unittest_util.h",
"image/image_unittest_util_ios.mm",
"image/image_unittest_util_mac.mm",
- "test/fontconfig_util_linux.cc",
- "test/fontconfig_util_linux.h",
"test/gfx_util.cc",
"test/gfx_util.h",
"test/icc_profiles.cc",
@@ -627,10 +628,6 @@ static_library("test_support") {
deps += [ "//third_party:freetype_harfbuzz" ]
}
-
- if (is_linux) {
- deps += [ "//third_party/fontconfig" ]
- }
}
test("gfx_unittests") {
@@ -793,7 +790,7 @@ test("gfx_unittests") {
if (!is_ios) {
deps += [
"//cc/paint",
- "//mojo/edk/system",
+ "//mojo/edk",
"//mojo/public/cpp/bindings",
"//ui/gfx/geometry/mojo:unit_test",
"//ui/gfx/image/mojo:unit_test",
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS
index 808d12b3ae0..1fa634730b4 100644
--- a/chromium/ui/gfx/DEPS
+++ b/chromium/ui/gfx/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+base",
"+cc/base",
"+cc/paint",
- "+device/vr/features/features.h",
+ "+device/vr/buildflags/buildflags.h",
"+skia/ext",
"+third_party/harfbuzz-ng",
"+third_party/skia",
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index ad40b66f057..e73caf84d43 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -20,6 +20,9 @@ per-file transform*=vollick@chromium.org
per-file interpolated_transform*=danakj@chromium.org
per-file interpolated_transform*=vollick@chromium.org
+# Skia geometry helpers.
+per-file skia_util*=danakj@chromium.org
+
# GPU memory buffer and GpuFence interfaces.
per-file gpu_fence*=reveman@chromium.org
per-file gpu_memory_buffer*=reveman@chromium.org
diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc
index 469b5260ce0..90342df9b79 100644
--- a/chromium/ui/gfx/animation/animation.cc
+++ b/chromium/ui/gfx/animation/animation.cc
@@ -4,7 +4,6 @@
#include "ui/gfx/animation/animation.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/animation_delegate.h"
diff --git a/chromium/ui/gfx/animation/animation_test_api.cc b/chromium/ui/gfx/animation/animation_test_api.cc
index b1c345dfedb..4f3c99d93df 100644
--- a/chromium/ui/gfx/animation/animation_test_api.cc
+++ b/chromium/ui/gfx/animation/animation_test_api.cc
@@ -4,7 +4,6 @@
#include "ui/gfx/animation/animation_test_api.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "ui/gfx/animation/animation.h"
diff --git a/chromium/ui/gfx/break_list.h b/chromium/ui/gfx/break_list.h
index 97d23c52955..cb3de2b76de 100644
--- a/chromium/ui/gfx/break_list.h
+++ b/chromium/ui/gfx/break_list.h
@@ -89,7 +89,7 @@ void BreakList<T>::ApplyValue(T value, const Range& range) {
return;
DCHECK(!breaks_.empty());
DCHECK(!range.is_reversed());
- DCHECK(Range(0, max_).Contains(range));
+ DCHECK(Range(0, static_cast<uint32_t>(max_)).Contains(range));
// Erase any breaks in |range|, then add start and end breaks as needed.
typename std::vector<Break>::iterator start = GetBreak(range.start());
diff --git a/chromium/ui/gfx/client_native_pixmap_factory.cc b/chromium/ui/gfx/client_native_pixmap_factory.cc
index f88b4fdeef3..7a4354f2507 100644
--- a/chromium/ui/gfx/client_native_pixmap_factory.cc
+++ b/chromium/ui/gfx/client_native_pixmap_factory.cc
@@ -6,30 +6,6 @@
namespace gfx {
-namespace {
-
-ClientNativePixmapFactory* g_instance = nullptr;
-
-} // namespace
-
-// static
-ClientNativePixmapFactory* ClientNativePixmapFactory::GetInstance() {
- return g_instance;
-}
-
-// static
-void ClientNativePixmapFactory::ResetInstance() {
- g_instance = nullptr;
-}
-
-// static
-void ClientNativePixmapFactory::SetInstance(
- ClientNativePixmapFactory* instance) {
- DCHECK(!g_instance);
- DCHECK(instance);
- g_instance = instance;
-}
-
ClientNativePixmapFactory::ClientNativePixmapFactory() {}
ClientNativePixmapFactory::~ClientNativePixmapFactory() {}
diff --git a/chromium/ui/gfx/client_native_pixmap_factory.h b/chromium/ui/gfx/client_native_pixmap_factory.h
index 8268566d5b0..fff5b4cd179 100644
--- a/chromium/ui/gfx/client_native_pixmap_factory.h
+++ b/chromium/ui/gfx/client_native_pixmap_factory.h
@@ -23,10 +23,6 @@ class Size;
// provide a client pixmap for non-GPU processes.
class GFX_EXPORT ClientNativePixmapFactory {
public:
- static ClientNativePixmapFactory* GetInstance();
- static void SetInstance(ClientNativePixmapFactory* instance);
- static void ResetInstance();
-
virtual ~ClientNativePixmapFactory();
// Returns true if format/usage configuration is supported.
diff --git a/chromium/ui/gfx/color_palette.h b/chromium/ui/gfx/color_palette.h
index 3c77e6a68c9..317174734d7 100644
--- a/chromium/ui/gfx/color_palette.h
+++ b/chromium/ui/gfx/color_palette.h
@@ -13,8 +13,6 @@ namespace gfx {
// as a visual flag for misbehaving code.
constexpr SkColor kPlaceholderColor = SK_ColorRED;
-constexpr SkColor kChromeIconGrey = SkColorSetRGB(0x5A, 0x5A, 0x5A);
-
// The number refers to the shade of darkness. Each color in the MD
// palette ranges from 100-900.
constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8);
@@ -22,6 +20,7 @@ constexpr SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4);
constexpr SkColor kGoogleBlue600 = SkColorSetRGB(0x1A, 0x73, 0xE8);
constexpr SkColor kGoogleBlue700 = SkColorSetRGB(0x19, 0x67, 0xD2);
constexpr SkColor kGoogleBlue900 = SkColorSetRGB(0x17, 0x4E, 0xA6);
+constexpr SkColor kGoogleBlueDark600 = SkColorSetRGB(0x25, 0x81, 0xDF);
constexpr SkColor kGoogleRed300 = SkColorSetRGB(0xF2, 0x8B, 0xB2);
constexpr SkColor kGoogleRed600 = SkColorSetRGB(0xD9, 0x30, 0x25);
constexpr SkColor kGoogleRed700 = SkColorSetRGB(0xC5, 0x22, 0x1F);
@@ -29,7 +28,9 @@ constexpr SkColor kGoogleRed800 = SkColorSetRGB(0xB3, 0x14, 0x12);
constexpr SkColor kGoogleRedDark600 = SkColorSetRGB(0xD3, 0x3B, 0x30);
constexpr SkColor kGoogleRedDark800 = SkColorSetRGB(0xB4, 0x1B, 0x1A);
constexpr SkColor kGoogleGreen300 = SkColorSetRGB(0x81, 0xC9, 0x95);
+constexpr SkColor kGoogleGreen600 = SkColorSetRGB(0x1E, 0x8E, 0x3E);
constexpr SkColor kGoogleGreen700 = SkColorSetRGB(0x18, 0x80, 0x38);
+constexpr SkColor kGoogleGreenDark600 = SkColorSetRGB(0x28, 0x99, 0x4F);
constexpr SkColor kGoogleYellow300 = SkColorSetRGB(0xFD, 0xD6, 0x63);
constexpr SkColor kGoogleYellow700 = SkColorSetRGB(0xF2, 0x99, 0x00);
constexpr SkColor kGoogleYellow900 = SkColorSetRGB(0xE3, 0x74, 0x00);
@@ -39,6 +40,12 @@ constexpr SkColor kGoogleGrey700 = SkColorSetRGB(0x5F, 0x63, 0x68);
constexpr SkColor kGoogleGrey800 = SkColorSetRGB(0x3C, 0x40, 0x43);
constexpr SkColor kGoogleGrey900 = SkColorSetRGB(0x20, 0x21, 0x24);
+// kChromeIconGrey is subject to change in the future, kGoogleGrey700 is set in
+// stone. If you're semantically looking for "the icon color Chrome uses" then
+// use kChromeIconGrey, if you're looking for GG700 grey specifically, use the
+// Google-grey constant directly.
+constexpr SkColor kChromeIconGrey = kGoogleGrey700;
+
// An alpha value for designating a control's disabled state. In specs this is
// sometimes listed as 0.38a.
constexpr SkAlpha kDisabledControlAlpha = 0x61;
diff --git a/chromium/ui/gfx/color_space.cc b/chromium/ui/gfx/color_space.cc
index 77458c930c6..0161da04c6a 100644
--- a/chromium/ui/gfx/color_space.cc
+++ b/chromium/ui/gfx/color_space.cc
@@ -38,6 +38,10 @@ base::LazyInstance<SkColorSpaceCache>::Leaky g_sk_color_space_cache =
base::LazyInstance<base::Lock>::Leaky g_sk_color_space_cache_lock =
LAZY_INSTANCE_INITIALIZER;
+static bool IsAlmostZero(float value) {
+ return std::abs(value) < std::numeric_limits<float>::epsilon();
+}
+
} // namespace
ColorSpace::ColorSpace() {}
@@ -306,7 +310,8 @@ size_t ColorSpace::GetHash() const {
std::string ColorSpace::ToString() const {
std::stringstream ss;
ss << std::fixed << std::setprecision(4);
- ss << "{primaries:";
+ if (primaries_ != PrimaryID::CUSTOM)
+ ss << "{primaries:";
switch (primaries_) {
PRINT_ENUM_CASE(PrimaryID, INVALID)
PRINT_ENUM_CASE(PrimaryID, BT709)
@@ -324,20 +329,29 @@ std::string ColorSpace::ToString() const {
PRINT_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
PRINT_ENUM_CASE(PrimaryID, WIDE_GAMUT_COLOR_SPIN)
case PrimaryID::CUSTOM:
- ss << "[";
- for (size_t i = 0; i < 3; ++i) {
- ss << "[";
- for (size_t j = 0; j < 3; ++j)
- ss << custom_primary_matrix_[3 * i + j] << ",";
- ss << "],";
- }
- ss << "]";
+ // |custom_primary_matrix_| is in column-major order.
+ const float sum_X = custom_primary_matrix_[0] +
+ custom_primary_matrix_[3] + custom_primary_matrix_[6];
+ const float sum_Y = custom_primary_matrix_[1] +
+ custom_primary_matrix_[4] + custom_primary_matrix_[7];
+ const float sum_Z = custom_primary_matrix_[2] +
+ custom_primary_matrix_[5] + custom_primary_matrix_[8];
+ if (IsAlmostZero(sum_X) || IsAlmostZero(sum_Y) || IsAlmostZero(sum_Z))
+ break;
+
+ ss << "{primaries_d50_referred: [[" << (custom_primary_matrix_[0] / sum_X)
+ << ", " << (custom_primary_matrix_[3] / sum_X) << "], "
+ << " [" << (custom_primary_matrix_[1] / sum_Y) << ", "
+ << (custom_primary_matrix_[4] / sum_Y) << "], "
+ << " [" << (custom_primary_matrix_[2] / sum_Z) << ", "
+ << (custom_primary_matrix_[5] / sum_Z) << "]]";
break;
}
ss << ", transfer:";
switch (transfer_) {
PRINT_ENUM_CASE(TransferID, INVALID)
PRINT_ENUM_CASE(TransferID, BT709)
+ PRINT_ENUM_CASE(TransferID, BT709_APPLE)
PRINT_ENUM_CASE(TransferID, GAMMA18)
PRINT_ENUM_CASE(TransferID, GAMMA22)
PRINT_ENUM_CASE(TransferID, GAMMA24)
@@ -759,6 +773,9 @@ bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
fn->fD = 0.040449937172f;
fn->fG = 2.400000000000f;
return true;
+ case ColorSpace::TransferID::BT709_APPLE:
+ fn->fG = 1.961000000000f;
+ return true;
case ColorSpace::TransferID::SMPTEST428_1:
fn->fA = 0.225615407568f;
fn->fE = -1.091041666667f;
@@ -835,18 +852,16 @@ void ColorSpace::GetTransferMatrix(SkMatrix44* matrix) const {
}
// BT2020_CL is a special case.
- // Basically we return a matrix that transforms RGB values
- // to RYB values. (We replace the green component with the
- // the luminance.) Later steps will compute the Cb & Cr values.
+ // Basically we return a matrix that transforms RYB values
+ // to YUV values. (Note that the green component have been replaced
+ // with the luminance.)
case ColorSpace::MatrixID::BT2020_CL: {
Kr = 0.2627f;
Kb = 0.0593f;
- float data[16] = {
- 1.0f, 0.0f, 0.0f, 0.0f, // R
- Kr, 1.0f - Kr - Kb, Kb, 0.0f, // Y
- 0.0f, 0.0f, 1.0f, 0.0f, // B
- 0.0f, 0.0f, 0.0f, 1.0f
- };
+ float data[16] = {1.0f, 0.0f, 0.0f, 0.0f, // R
+ Kr, 1.0f - Kr - Kb, Kb, 0.0f, // Y
+ 0.0f, 0.0f, 1.0f, 0.0f, // B
+ 0.0f, 0.0f, 0.0f, 1.0f};
matrix->setRowMajorf(data);
return;
}
@@ -912,6 +927,28 @@ void ColorSpace::GetRangeAdjustMatrix(SkMatrix44* matrix) const {
}
}
+bool ColorSpace::ToSkYUVColorSpace(SkYUVColorSpace* out) {
+ if (range_ == RangeID::FULL) {
+ *out = kJPEG_SkYUVColorSpace;
+ return true;
+ }
+ switch (matrix_) {
+ case MatrixID::BT709:
+ *out = kRec709_SkYUVColorSpace;
+ return true;
+
+ case MatrixID::BT470BG:
+ case MatrixID::SMPTE170M:
+ case MatrixID::SMPTE240M:
+ *out = kRec601_SkYUVColorSpace;
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
std::ostream& operator<<(std::ostream& out, const ColorSpace& color_space) {
return out << color_space.ToString();
}
diff --git a/chromium/ui/gfx/color_space.h b/chromium/ui/gfx/color_space.h
index 561cbc74e2a..3c30511ec9e 100644
--- a/chromium/ui/gfx/color_space.h
+++ b/chromium/ui/gfx/color_space.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/color_space_export.h"
namespace IPC {
@@ -56,6 +57,9 @@ class COLOR_SPACE_EXPORT ColorSpace {
enum class TransferID : uint8_t {
INVALID,
BT709,
+ // On macOS, BT709 hardware decoded video frames, when displayed as
+ // overlays, will have a transfer function of gamma=1.961.
+ BT709_APPLE,
GAMMA18,
GAMMA22,
GAMMA24,
@@ -187,6 +191,10 @@ class COLOR_SPACE_EXPORT ColorSpace {
// range, and unspecified spaces.
sk_sp<SkColorSpace> ToSkColorSpace() const;
+ // For YUV color spaces, return the closest SkYUVColorSpace.
+ // Returns true if a close match is found.
+ bool ToSkYUVColorSpace(SkYUVColorSpace* out);
+
void GetPrimaryMatrix(SkMatrix44* to_XYZD50) const;
bool GetTransferFunction(SkColorSpaceTransferFn* fn) const;
bool GetInverseTransferFunction(SkColorSpaceTransferFn* fn) const;
diff --git a/chromium/ui/gfx/color_space_unittest.cc b/chromium/ui/gfx/color_space_unittest.cc
index 96dd37d8228..c4a955787fe 100644
--- a/chromium/ui/gfx/color_space_unittest.cc
+++ b/chromium/ui/gfx/color_space_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <cmath>
+#include <tuple>
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -80,13 +81,13 @@ TEST(ColorSpace, RGBToYUV) {
}
}
-typedef std::tr1::tuple<ColorSpace::TransferID, size_t> TableTestData;
+typedef std::tuple<ColorSpace::TransferID, size_t> TableTestData;
class ColorSpaceTableTest : public testing::TestWithParam<TableTestData> {};
TEST_P(ColorSpaceTableTest, ApproximateTransferFn) {
- ColorSpace::TransferID transfer_id = std::tr1::get<0>(GetParam());
- const size_t table_size = std::tr1::get<1>(GetParam());
+ ColorSpace::TransferID transfer_id = std::get<0>(GetParam());
+ const size_t table_size = std::get<1>(GetParam());
gfx::ColorSpace color_space(ColorSpace::PrimaryID::BT709, transfer_id);
SkColorSpaceTransferFn tr_fn;
diff --git a/chromium/ui/gfx/color_space_win.cc b/chromium/ui/gfx/color_space_win.cc
index f35f2eba010..84507a6bc6c 100644
--- a/chromium/ui/gfx/color_space_win.cc
+++ b/chromium/ui/gfx/color_space_win.cc
@@ -118,6 +118,7 @@ DXVA2_ExtendedFormat ColorSpaceWin::GetExtendedFormat(
case gfx::ColorSpace::TransferID::SMPTEST2084:
case gfx::ColorSpace::TransferID::SMPTEST428_1:
case gfx::ColorSpace::TransferID::ARIB_STD_B67:
+ case gfx::ColorSpace::TransferID::BT709_APPLE:
case gfx::ColorSpace::TransferID::GAMMA18:
case gfx::ColorSpace::TransferID::GAMMA24:
case gfx::ColorSpace::TransferID::SMPTEST2084_NON_HDR:
diff --git a/chromium/ui/gfx/color_transform.cc b/chromium/ui/gfx/color_transform.cc
index cf3aa80546e..fb64a68d04e 100644
--- a/chromium/ui/gfx/color_transform.cc
+++ b/chromium/ui/gfx/color_transform.cc
@@ -11,7 +11,6 @@
#include <sstream>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorSpaceXform.h"
@@ -275,8 +274,9 @@ class ColorTransformInternal : public ColorTransform {
gfx::ColorSpace GetDstColorSpace() const override { return dst_; };
void Transform(TriStim* colors, size_t num) const override {
- for (const auto& step : steps_)
+ for (const auto& step : steps_) {
step->Transform(colors, num);
+ }
}
bool CanGetShaderSource() const override;
std::string GetShaderSource() const override;
@@ -443,8 +443,6 @@ class ColorTransformSkTransferFn : public ColorTransformPerChannelTransferFn {
// ColorTransformPerChannelTransferFn implementation:
float Evaluate(float v) const override {
// Note that the sign-extension is performed by the caller.
- if (v < 0.f)
- return 0.f;
return SkTransferFnEvalUnclamped(fn_, v);
}
void AppendTransferShaderSource(std::stringstream* result) const override {
@@ -473,14 +471,9 @@ class ColorTransformSkTransferFn : public ColorTransformPerChannelTransferFn {
if (std::abs(fn_.fE) > kEpsilon)
nonlinear = nonlinear + " + " + Str(fn_.fE);
- // Add both parts, skipping the if clause if possible.
- if (fn_.fD > kEpsilon) {
- *result << " if (v < " << Str(fn_.fD) << ")" << endl;
- *result << " return " << linear << ";" << endl;
- *result << " return " << nonlinear << ";" << endl;
- } else {
- *result << " return " << nonlinear << ";" << endl;
- }
+ *result << " if (v < " << Str(fn_.fD) << ")" << endl;
+ *result << " return " << linear << ";" << endl;
+ *result << " return " << nonlinear << ";" << endl;
}
private:
@@ -733,7 +726,7 @@ class ColorTransformToBT2020CL : public ColorTransformStep {
} else {
V = R_Y / (2.0 * 0.4969);
}
- RYB[i] = ColorTransform::TriStim(RYB[i].y(), U, V);
+ RYB[i] = ColorTransform::TriStim(RYB[i].y(), U + 0.5, V + 0.5);
}
}
@@ -761,11 +754,11 @@ class ColorTransformFromBT2020CL : public ColorTransformStep {
return;
for (size_t i = 0; i < num; i++) {
float Y = YUV[i].x();
- float U = YUV[i].y();
- float V = YUV[i].z();
+ float U = YUV[i].y() - 0.5;
+ float V = YUV[i].z() - 0.5;
float B_Y, R_Y;
if (U <= 0) {
- B_Y = Y * (-2.0 * -0.9702);
+ B_Y = U * (-2.0 * -0.9702);
} else {
B_Y = U * (2.0 * 0.7910);
}
@@ -775,7 +768,7 @@ class ColorTransformFromBT2020CL : public ColorTransformStep {
R_Y = V * (2.0 * 0.4969);
}
// Return an RYB value, later steps will fix it.
- YUV[i] = ColorTransform::TriStim(R_Y + Y, YUV[i].x(), B_Y + Y);
+ YUV[i] = ColorTransform::TriStim(R_Y + Y, Y, B_Y + Y);
}
}
bool CanAppendShaderSource() override { return true; }
@@ -785,12 +778,12 @@ class ColorTransformFromBT2020CL : public ColorTransformStep {
*hdr << "vec3 BT2020_YUV_to_RYB_Step" << step_index << "(vec3 color) {"
<< endl;
*hdr << " float Y = color.x;" << endl;
- *hdr << " float U = color.y;" << endl;
- *hdr << " float V = color.z;" << endl;
+ *hdr << " float U = color.y - 0.5;" << endl;
+ *hdr << " float V = color.z - 0.5;" << endl;
*hdr << " float B_Y = 0.0;" << endl;
*hdr << " float R_Y = 0.0;" << endl;
*hdr << " if (U <= 0.0) {" << endl;
- *hdr << " B_Y = Y * (-2.0 * -0.9702);" << endl;
+ *hdr << " B_Y = U * (-2.0 * -0.9702);" << endl;
*hdr << " } else {" << endl;
*hdr << " B_Y = U * (2.0 * 0.7910);" << endl;
*hdr << " }" << endl;
@@ -843,8 +836,13 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
steps_.push_back(
std::make_unique<ColorTransformMatrix>(GetRangeAdjustMatrix(src)));
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(Invert(GetTransferMatrix(src))));
+ if (src.matrix_ == 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))));
+ }
// 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
@@ -865,7 +863,8 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
if (src.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
- steps_.push_back(std::make_unique<ColorTransformFromBT2020CL>());
+ steps_.push_back(
+ std::make_unique<ColorTransformMatrix>(Invert(GetTransferMatrix(src))));
}
steps_.push_back(
std::make_unique<ColorTransformMatrix>(GetPrimaryTransform(src)));
@@ -874,7 +873,8 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
std::make_unique<ColorTransformMatrix>(Invert(GetPrimaryTransform(dst))));
if (dst.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
- steps_.push_back(std::make_unique<ColorTransformToBT2020CL>());
+ steps_.push_back(
+ std::make_unique<ColorTransformMatrix>(GetTransferMatrix(dst)));
}
SkColorSpaceTransferFn dst_from_linear_fn;
@@ -885,8 +885,12 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
steps_.push_back(std::make_unique<ColorTransformFromLinear>(dst.transfer_));
}
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(GetTransferMatrix(dst)));
+ if (dst.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
+ steps_.push_back(std::make_unique<ColorTransformToBT2020CL>());
+ } else {
+ steps_.push_back(
+ std::make_unique<ColorTransformMatrix>(GetTransferMatrix(dst)));
+ }
steps_.push_back(std::make_unique<ColorTransformMatrix>(
Invert(GetRangeAdjustMatrix(dst))));
diff --git a/chromium/ui/gfx/color_transform_unittest.cc b/chromium/ui/gfx/color_transform_unittest.cc
index 34cd62aba6c..aa5a3de5d1d 100644
--- a/chromium/ui/gfx/color_transform_unittest.cc
+++ b/chromium/ui/gfx/color_transform_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <tuple>
+
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/color_space.h"
@@ -98,6 +100,36 @@ TEST(SimpleColorSpace, BT709toSRGB) {
EXPECT_GT(tmp.z(), tmp.y());
}
+TEST(SimpleColorSpace, BT2020CLtoBT2020RGB) {
+ ColorSpace bt2020cl(
+ ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::BT2020_10,
+ ColorSpace::MatrixID::BT2020_CL, ColorSpace::RangeID::LIMITED);
+ ColorSpace bt2020rgb(ColorSpace::PrimaryID::BT2020,
+ ColorSpace::TransferID::BT2020_10,
+ ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
+ ColorSpace sRGB = ColorSpace::CreateSRGB();
+ std::unique_ptr<ColorTransform> t(ColorTransform::NewColorTransform(
+ bt2020cl, bt2020rgb, ColorTransform::Intent::INTENT_ABSOLUTE));
+
+ ColorTransform::TriStim tmp(16.0f / 255.0f, 0.5f, 0.5f);
+ t->Transform(&tmp, 1);
+ EXPECT_NEAR(tmp.x(), 0.0f, 0.001f);
+ EXPECT_NEAR(tmp.y(), 0.0f, 0.001f);
+ EXPECT_NEAR(tmp.z(), 0.0f, 0.001f);
+
+ tmp = ColorTransform::TriStim(235.0f / 255.0f, 0.5f, 0.5f);
+ t->Transform(&tmp, 1);
+ EXPECT_NEAR(tmp.x(), 1.0f, 0.001f);
+ EXPECT_NEAR(tmp.y(), 1.0f, 0.001f);
+ EXPECT_NEAR(tmp.z(), 1.0f, 0.001f);
+
+ // Test a blue color
+ tmp = ColorTransform::TriStim(128.0f / 255.0f, 240.0f / 255.0f, 0.5f);
+ t->Transform(&tmp, 1);
+ EXPECT_GT(tmp.z(), tmp.x());
+ EXPECT_GT(tmp.z(), tmp.y());
+}
+
TEST(SimpleColorSpace, TransferFnCancel) {
ColorSpace::PrimaryID primary = ColorSpace::PrimaryID::BT709;
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::RGB;
@@ -380,55 +412,32 @@ TEST(SimpleColorSpace, DefaultToSRGB) {
EXPECT_EQ(t2->NumberOfStepsForTesting(), 0u);
}
-// This tests to make sure that we don't emit the "if" or "pow" parts of a
+// This tests to make sure that we don't emit "pow" parts of a
// transfer function unless necessary.
TEST(SimpleColorSpace, ShaderSourceTrFnOptimizations) {
SkMatrix44 primaries;
gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&primaries);
- SkColorSpaceTransferFn fn_no_pow_no_if = {
+ SkColorSpaceTransferFn fn_no_pow = {
1.f, 2.f, 0.f, 1.f, 0.f, 0.f, 0.f,
};
- SkColorSpaceTransferFn fn_no_pow_yes_if = {
- 1.f, 2.f, 0.f, 1.f, 0.5f, 0.f, 0.f,
- };
- SkColorSpaceTransferFn fn_yes_pow_no_if = {
+ SkColorSpaceTransferFn fn_yes_pow = {
2.f, 2.f, 0.f, 1.f, 0.f, 0.f, 0.f,
};
- SkColorSpaceTransferFn fn_yes_pow_yes_if = {
- 2.f, 2.f, 0.f, 1.f, 0.5f, 0.f, 0.f,
- };
-
gfx::ColorSpace src;
gfx::ColorSpace dst = gfx::ColorSpace::CreateXYZD50();
std::string shader_string;
- src = gfx::ColorSpace::CreateCustom(primaries, fn_no_pow_no_if);
- shader_string = ColorTransform::NewColorTransform(
- src, dst, ColorTransform::Intent::INTENT_PERCEPTUAL)
- ->GetShaderSource();
- EXPECT_EQ(shader_string.find("if ("), std::string::npos);
- EXPECT_EQ(shader_string.find("pow("), std::string::npos);
-
- src = gfx::ColorSpace::CreateCustom(primaries, fn_no_pow_yes_if);
+ src = gfx::ColorSpace::CreateCustom(primaries, fn_no_pow);
shader_string = ColorTransform::NewColorTransform(
src, dst, ColorTransform::Intent::INTENT_PERCEPTUAL)
->GetShaderSource();
- EXPECT_NE(shader_string.find("if ("), std::string::npos);
EXPECT_EQ(shader_string.find("pow("), std::string::npos);
- src = gfx::ColorSpace::CreateCustom(primaries, fn_yes_pow_no_if);
- shader_string = ColorTransform::NewColorTransform(
- src, dst, ColorTransform::Intent::INTENT_PERCEPTUAL)
- ->GetShaderSource();
- EXPECT_EQ(shader_string.find("if ("), std::string::npos);
- EXPECT_NE(shader_string.find("pow("), std::string::npos);
-
- src = gfx::ColorSpace::CreateCustom(primaries, fn_yes_pow_yes_if);
+ src = gfx::ColorSpace::CreateCustom(primaries, fn_yes_pow);
shader_string = ColorTransform::NewColorTransform(
src, dst, ColorTransform::Intent::INTENT_PERCEPTUAL)
->GetShaderSource();
- EXPECT_NE(shader_string.find("if ("), std::string::npos);
EXPECT_NE(shader_string.find("pow("), std::string::npos);
}
@@ -456,6 +465,8 @@ TEST(SimpleColorSpace, MAYBE_SampleShaderSource) {
" return pow(9.47867334e-01 * v + 5.21326549e-02, 2.40000010e+00);\n"
"}\n"
"float TransferFn3(float v) {\n"
+ " if (v < 0.00000000e+00)\n"
+ " return v;\n"
" return pow(v, 3.57142866e-01);\n"
"}\n"
"vec3 DoColorConversion(vec3 color) {\n"
@@ -577,21 +588,21 @@ INSTANTIATE_TEST_CASE_P(ColorSpace,
ExtendedTransferTest,
testing::ValuesIn(extended_transfers));
-typedef std::tr1::tuple<ColorSpace::PrimaryID,
- ColorSpace::TransferID,
- ColorSpace::MatrixID,
- ColorSpace::RangeID,
- ColorTransform::Intent>
+typedef std::tuple<ColorSpace::PrimaryID,
+ ColorSpace::TransferID,
+ ColorSpace::MatrixID,
+ ColorSpace::RangeID,
+ ColorTransform::Intent>
ColorSpaceTestData;
class ColorSpaceTest : public testing::TestWithParam<ColorSpaceTestData> {
public:
ColorSpaceTest()
- : color_space_(std::tr1::get<0>(GetParam()),
- std::tr1::get<1>(GetParam()),
- std::tr1::get<2>(GetParam()),
- std::tr1::get<3>(GetParam())),
- intent_(std::tr1::get<4>(GetParam())) {}
+ : color_space_(std::get<0>(GetParam()),
+ std::get<1>(GetParam()),
+ std::get<2>(GetParam()),
+ std::get<3>(GetParam())),
+ intent_(std::get<4>(GetParam())) {}
protected:
ColorSpace color_space_;
diff --git a/chromium/ui/gfx/color_utils.cc b/chromium/ui/gfx/color_utils.cc
index e6f537eda2a..c67023bd1cb 100644
--- a/chromium/ui/gfx/color_utils.cc
+++ b/chromium/ui/gfx/color_utils.cc
@@ -336,15 +336,9 @@ bool IsInvertedColorScheme() {
#endif // !defined(OS_WIN)
SkColor DeriveDefaultIconColor(SkColor text_color) {
- // Lighten a dark color but leave it fully opaque.
- if (IsDark(text_color)) {
- // For black text, this comes out to kChromeIconGrey.
- return color_utils::AlphaBlend(SK_ColorWHITE, text_color,
- SkColorGetR(gfx::kChromeIconGrey));
- }
- // For a light color, just reduce opacity.
- return SkColorSetA(text_color,
- static_cast<int>(0.8f * SkColorGetA(text_color)));
+ // Lighten dark colors and brighten light colors. The alpha value here (0x4c)
+ // is chosen to generate a value close to GoogleGrey700 from GoogleGrey900.
+ return BlendTowardOppositeLuma(text_color, 0x4c);
}
std::string SkColorToRgbaString(SkColor color) {
diff --git a/chromium/ui/gfx/decorated_text_mac.h b/chromium/ui/gfx/decorated_text_mac.h
new file mode 100644
index 00000000000..ad1aa59b1d7
--- /dev/null
+++ b/chromium/ui/gfx/decorated_text_mac.h
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_DECORATED_TEXT_MAC_H_
+#define UI_GFX_DECORATED_TEXT_MAC_H_
+
+#include "ui/gfx/gfx_export.h"
+
+@class NSAttributedString;
+
+namespace gfx {
+
+struct DecoratedText;
+
+// Returns a NSAttributedString from |decorated_text|.
+GFX_EXPORT NSAttributedString* GetAttributedStringFromDecoratedText(
+ const DecoratedText& decorated_text);
+
+} // namespace gfx
+
+#endif // UI_GFX_DECORATED_TEXT_MAC_H_ \ No newline at end of file
diff --git a/chromium/ui/gfx/decorated_text_mac.mm b/chromium/ui/gfx/decorated_text_mac.mm
new file mode 100644
index 00000000000..80942a61f8f
--- /dev/null
+++ b/chromium/ui/gfx/decorated_text_mac.mm
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/gfx/decorated_text_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ui/gfx/decorated_text.h"
+
+namespace gfx {
+
+NSAttributedString* GetAttributedStringFromDecoratedText(
+ const DecoratedText& decorated_text) {
+ base::scoped_nsobject<NSMutableAttributedString> str(
+ [[NSMutableAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(decorated_text.text)]);
+ [str beginEditing];
+
+ NSValue* const line_style =
+ @(NSUnderlineStyleSingle | NSUnderlinePatternSolid);
+
+ for (const auto& attribute : decorated_text.attributes) {
+ DCHECK(!attribute.range.is_reversed());
+ DCHECK_LE(attribute.range.end(), [str length]);
+
+ NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
+ NSRange range = attribute.range.ToNSRange();
+
+ if (attribute.font.GetNativeFont())
+ attrs[NSFontAttributeName] = attribute.font.GetNativeFont();
+
+ // NSFont does not have underline as an attribute. Hence handle it
+ // separately.
+ const bool underline = attribute.font.GetStyle() & gfx::Font::UNDERLINE;
+ if (underline)
+ attrs[NSUnderlineStyleAttributeName] = line_style;
+
+ if (attribute.strike)
+ attrs[NSStrikethroughStyleAttributeName] = line_style;
+
+ [str setAttributes:attrs range:range];
+ }
+
+ [str endEditing];
+ return str.autorelease();
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc
index e2bcf215ecd..68e6c40c155 100644
--- a/chromium/ui/gfx/font_list_unittest.cc
+++ b/chromium/ui/gfx/font_list_unittest.cc
@@ -299,9 +299,10 @@ TEST(FontListTest, MAYBE_Fonts_DeriveWithSizeDelta) {
#endif
TEST(FontListTest, MAYBE_Fonts_GetHeight_GetBaseline) {
// If a font list has only one font, the height and baseline must be the same.
- Font font1("Verdana", 16);
- ASSERT_EQ("verdana", base::ToLowerASCII(font1.GetActualFontNameForTesting()));
- FontList font_list1("Verdana, 16px");
+ Font font1(kTestFontName, 16);
+ ASSERT_EQ(base::ToLowerASCII(kTestFontName),
+ base::ToLowerASCII(font1.GetActualFontNameForTesting()));
+ FontList font_list1(std::string(kTestFontName) + ", 16px");
EXPECT_EQ(font1.GetHeight(), font_list1.GetHeight());
EXPECT_EQ(font1.GetBaseline(), font_list1.GetBaseline());
diff --git a/chromium/ui/gfx/font_names_testing.cc b/chromium/ui/gfx/font_names_testing.cc
index 09ec558cd7b..8385fe39c3b 100644
--- a/chromium/ui/gfx/font_names_testing.cc
+++ b/chromium/ui/gfx/font_names_testing.cc
@@ -9,13 +9,19 @@
namespace gfx {
#if defined(OS_LINUX)
+const char kTestFontName[] = "Arimo";
+#else
+const char kTestFontName[] = "Arial";
+#endif
+
+#if defined(OS_LINUX)
const char kSymbolFontName[] = "DejaVu Sans";
#else
const char kSymbolFontName[] = "Symbol";
#endif
#if defined(OS_LINUX)
-const char kCJKFontName[] = "IPAMincho";
+const char kCJKFontName[] = "Noto Sans CJK JP";
#elif defined(OS_MACOSX)
const char kCJKFontName[] = "Heiti SC";
#else
diff --git a/chromium/ui/gfx/font_names_testing.h b/chromium/ui/gfx/font_names_testing.h
index 34c96bef6ad..85a66c3323e 100644
--- a/chromium/ui/gfx/font_names_testing.h
+++ b/chromium/ui/gfx/font_names_testing.h
@@ -7,6 +7,7 @@
namespace gfx {
+extern const char kTestFontName[];
extern const char kSymbolFontName[];
extern const char kCJKFontName[];
diff --git a/chromium/ui/gfx/font_render_params.h b/chromium/ui/gfx/font_render_params.h
index 39d72e35203..8cda96de768 100644
--- a/chromium/ui/gfx/font_render_params.h
+++ b/chromium/ui/gfx/font_render_params.h
@@ -9,7 +9,7 @@
#include <vector>
#include "build/build_config.h"
-#include "device/vr/features/features.h"
+#include "device/vr/buildflags/buildflags.h"
#include "third_party/skia/include/core/SkFontLCDConfig.h"
#include "ui/gfx/font.h"
#include "ui/gfx/gfx_export.h"
diff --git a/chromium/ui/gfx/font_render_params_linux_unittest.cc b/chromium/ui/gfx/font_render_params_linux_unittest.cc
index 34732edf7d7..32db9e82aa2 100644
--- a/chromium/ui/gfx/font_render_params_linux_unittest.cc
+++ b/chromium/ui/gfx/font_render_params_linux_unittest.cc
@@ -4,14 +4,16 @@
#include "ui/gfx/font_render_params.h"
+#include <fontconfig/fontconfig.h>
+
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/test/fontconfig_util_linux.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
#include "ui/gfx/linux_font_delegate.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
namespace gfx {
@@ -60,7 +62,6 @@ class TestFontDelegate : public LinuxFontDelegate {
class FontRenderParamsTest : public testing::Test {
public:
FontRenderParamsTest() {
- SetUpFontconfig();
CHECK(temp_dir_.CreateUniqueTempDir());
original_font_delegate_ = LinuxFontDelegate::instance();
LinuxFontDelegate::SetInstance(&test_font_delegate_);
@@ -70,7 +71,17 @@ class FontRenderParamsTest : public testing::Test {
~FontRenderParamsTest() override {
LinuxFontDelegate::SetInstance(
const_cast<LinuxFontDelegate*>(original_font_delegate_));
- TearDownFontconfig();
+ }
+
+ void SetUp() override {
+ // Fontconfig should already be set up by the test runner.
+ DCHECK(FcConfigGetCurrent());
+ }
+
+ void TearDown() override {
+ // We might have made a mess introducing new fontconfig settings. Reset the
+ // state of fontconfig for the next test.
+ base::SetUpFontconfig();
}
protected:
@@ -83,7 +94,6 @@ class FontRenderParamsTest : public testing::Test {
};
TEST_F(FontRenderParamsTest, Default) {
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) +
@@ -91,36 +101,36 @@ TEST_F(FontRenderParamsTest, Default) {
// match (since this is the style generally used in
// /etc/fonts/conf.d).
kFontconfigMatchFontHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("autohint", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigEditStanza("autohint", "bool", "true") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
kFontconfigMatchFooter +
- // Add a font match for Arial. Since it specifies a family, it
- // shouldn't
- // take effect when querying default settings.
+ // Add a font match for Arimo. Since it specifies a family, it
+ // shouldn't take effect when querying default settings.
kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("autohint", "bool", "false") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
+ base::CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigEditStanza("autohint", "bool", "false") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+ base::CreateFontconfigEditStanza("rgba", "const", "none") +
kFontconfigMatchFooter +
// Add font matches for fonts between 10 and 20 points or pixels.
- // Since
- // they specify sizes, they also should not affect the defaults.
+ // Since they specify sizes, they also should not affect the defaults.
kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("size", "more_eq", "double", "10.0") +
- CreateFontconfigTestStanza("size", "less_eq", "double", "20.0") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
+ base::CreateFontconfigTestStanza("size", "more_eq", "double",
+ "10.0") +
+ base::CreateFontconfigTestStanza("size", "less_eq", "double",
+ "20.0") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "false") +
kFontconfigMatchFooter + kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("pixel_size", "more_eq", "double",
- "10.0") +
- CreateFontconfigTestStanza("pixel_size", "less_eq", "double",
- "20.0") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
+ base::CreateFontconfigTestStanza("pixel_size", "more_eq", "double",
+ "10.0") +
+ base::CreateFontconfigTestStanza("pixel_size", "less_eq", "double",
+ "20.0") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "false") +
kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParams params = GetFontRenderParams(
@@ -135,21 +145,21 @@ TEST_F(FontRenderParamsTest, Default) {
}
TEST_F(FontRenderParamsTest, Size) {
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
+ ASSERT_TRUE(base::LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+ base::CreateFontconfigEditStanza("rgba", "const", "none") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
+ base::CreateFontconfigTestStanza("pixelsize", "less_eq", "double",
+ "10") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "false") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ base::CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
kFontconfigMatchFooter + kFontconfigFileFooter));
// The defaults should be used when the supplied size isn't matched by the
@@ -179,22 +189,21 @@ TEST_F(FontRenderParamsTest, Size) {
}
TEST_F(FontRenderParamsTest, Style) {
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
// Load a config that disables subpixel rendering for bold text and disables
// hinting for italic text.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
+ base::CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
+ base::CreateFontconfigEditStanza("rgba", "const", "none") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
- CreateFontconfigEditStanza("hinting", "bool", "false") +
+ base::CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "false") +
kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
@@ -230,10 +239,10 @@ TEST_F(FontRenderParamsTest, Scalable) {
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "false") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
kFontconfigMatchFooter + kFontconfigFileFooter));
// Check that we specifically ask how scalable fonts should be rendered.
@@ -243,15 +252,15 @@ TEST_F(FontRenderParamsTest, Scalable) {
}
TEST_F(FontRenderParamsTest, UseBitmaps) {
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
// Load a config that enables embedded bitmaps for fonts <= 10 pixels.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
+ base::CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
- CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
+ base::CreateFontconfigTestStanza("pixelsize", "less_eq", "double",
+ "10") +
+ base::CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
@@ -269,10 +278,10 @@ TEST_F(FontRenderParamsTest, ForceFullHintingWhenAntialiasingIsDisabled) {
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- CreateFontconfigEditStanza("hinting", "bool", "false") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "false") +
+ base::CreateFontconfigEditStanza("hinting", "bool", "false") +
+ base::CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
+ base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
kFontconfigMatchFooter + kFontconfigFileFooter));
// Full hinting should be forced. See the comment in GetFontRenderParams() for
@@ -318,7 +327,7 @@ TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) {
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
+ base::CreateFontconfigEditStanza("antialias", "bool", "true") +
kFontconfigMatchFooter + kFontconfigFileFooter));
// The subpixel rendering setting from the delegate should make it through.
@@ -328,7 +337,9 @@ TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) {
}
TEST_F(FontRenderParamsTest, NoFontconfigMatch) {
- // Don't load a Fontconfig configuration.
+ // A default configuration was set up globally. Reset it to a blank config.
+ FcConfigSetCurrent(FcConfigCreate());
+
FontRenderParams system_params;
system_params.antialiasing = true;
system_params.hinting = FontRenderParams::HINTING_MEDIUM;
@@ -336,7 +347,7 @@ TEST_F(FontRenderParamsTest, NoFontconfigMatch) {
test_font_delegate_.set_params(system_params);
FontRenderParamsQuery query;
- query.families.push_back("Arial");
+ query.families.push_back("Arimo");
query.families.push_back("Times New Roman");
query.pixel_size = 10;
std::string suggested_family;
@@ -350,43 +361,39 @@ TEST_F(FontRenderParamsTest, NoFontconfigMatch) {
}
TEST_F(FontRenderParamsTest, MissingFamily) {
- // With Arial and Verdana installed, request (in order) Helvetica, Arial, and
- // Verdana and check that Arial is returned.
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf"));
+ // With Arimo and Verdana installed, request (in order) Helvetica, Arimo, and
+ // Verdana and check that Arimo is returned.
FontRenderParamsQuery query;
query.families.push_back("Helvetica");
- query.families.push_back("Arial");
+ query.families.push_back("Arimo");
query.families.push_back("Verdana");
std::string suggested_family;
GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Arial", suggested_family);
+ EXPECT_EQ("Arimo", suggested_family);
}
TEST_F(FontRenderParamsTest, SubstituteFamily) {
- // Configure Fontconfig to use Verdana for both Helvetica and Arial.
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf"));
+ // Configure Fontconfig to use Tinos for both Helvetica and Arimo.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
temp_dir_.GetPath(),
std::string(kFontconfigFileHeader) +
- CreateFontconfigAliasStanza("Helvetica", "Verdana") +
+ base::CreateFontconfigAliasStanza("Helvetica", "Tinos") +
kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
- CreateFontconfigEditStanza("family", "string", "Verdana") +
+ base::CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
+ base::CreateFontconfigEditStanza("family", "string", "Tinos") +
kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
query.families.push_back("Helvetica");
std::string suggested_family;
GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Verdana", suggested_family);
+ EXPECT_EQ("Tinos", suggested_family);
query.families.clear();
- query.families.push_back("Arial");
+ query.families.push_back("Arimo");
suggested_family.clear();
GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Verdana", suggested_family);
+ EXPECT_EQ("Tinos", suggested_family);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/font_unittest.cc b/chromium/ui/gfx/font_unittest.cc
index c74aae18f14..9b9eae0194d 100644
--- a/chromium/ui/gfx/font_unittest.cc
+++ b/chromium/ui/gfx/font_unittest.cc
@@ -54,14 +54,15 @@ int ScopedMinimumFontSizeCallback::minimum_size_ = 0;
#define MAYBE_LoadArial LoadArial
#endif
TEST_F(FontTest, MAYBE_LoadArial) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_IOS)
EXPECT_TRUE(cf.GetNativeFont());
#endif
EXPECT_EQ(cf.GetStyle(), Font::NORMAL);
EXPECT_EQ(cf.GetFontSize(), 16);
- EXPECT_EQ(cf.GetFontName(), "Arial");
- EXPECT_EQ("arial", base::ToLowerASCII(cf.GetActualFontNameForTesting()));
+ EXPECT_EQ(cf.GetFontName(), kTestFontName);
+ EXPECT_EQ(base::ToLowerASCII(kTestFontName),
+ base::ToLowerASCII(cf.GetActualFontNameForTesting()));
}
#if defined(OS_ANDROID)
@@ -70,14 +71,15 @@ TEST_F(FontTest, MAYBE_LoadArial) {
#define MAYBE_LoadArialBold LoadArialBold
#endif
TEST_F(FontTest, MAYBE_LoadArialBold) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
Font bold(cf.Derive(0, Font::NORMAL, Font::Weight::BOLD));
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_IOS)
EXPECT_TRUE(bold.GetNativeFont());
#endif
EXPECT_EQ(bold.GetStyle(), Font::NORMAL);
EXPECT_EQ(bold.GetWeight(), Font::Weight::BOLD);
- EXPECT_EQ("arial", base::ToLowerASCII(cf.GetActualFontNameForTesting()));
+ EXPECT_EQ(base::ToLowerASCII(kTestFontName),
+ base::ToLowerASCII(cf.GetActualFontNameForTesting()));
}
#if defined(OS_ANDROID)
@@ -86,7 +88,7 @@ TEST_F(FontTest, MAYBE_LoadArialBold) {
#define MAYBE_Ascent Ascent
#endif
TEST_F(FontTest, MAYBE_Ascent) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
EXPECT_GT(cf.GetBaseline(), 2);
EXPECT_LE(cf.GetBaseline(), 22);
}
@@ -97,7 +99,7 @@ TEST_F(FontTest, MAYBE_Ascent) {
#define MAYBE_Height Height
#endif
TEST_F(FontTest, MAYBE_Height) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
EXPECT_GE(cf.GetHeight(), 16);
// TODO(akalin): Figure out why height is so large on Linux.
EXPECT_LE(cf.GetHeight(), 26);
@@ -109,7 +111,7 @@ TEST_F(FontTest, MAYBE_Height) {
#define MAYBE_CapHeight CapHeight
#endif
TEST_F(FontTest, MAYBE_CapHeight) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
EXPECT_GT(cf.GetCapHeight(), 0);
EXPECT_GT(cf.GetCapHeight(), cf.GetHeight() / 2);
EXPECT_LT(cf.GetCapHeight(), cf.GetBaseline());
@@ -121,7 +123,7 @@ TEST_F(FontTest, MAYBE_CapHeight) {
#define MAYBE_AvgWidths AvgWidths
#endif
TEST_F(FontTest, MAYBE_AvgWidths) {
- Font cf("Arial", 16);
+ Font cf(kTestFontName, 16);
EXPECT_EQ(cf.GetExpectedTextWidth(0), 0);
EXPECT_GT(cf.GetExpectedTextWidth(1), cf.GetExpectedTextWidth(0));
EXPECT_GT(cf.GetExpectedTextWidth(2), cf.GetExpectedTextWidth(1));
@@ -140,8 +142,9 @@ TEST_F(FontTest, MAYBE_AvgWidths) {
// fonts may be installed but still need enabling in Font Book.app.
// http://crbug.com/347429
TEST_F(FontTest, MAYBE_GetActualFontNameForTesting) {
- Font arial("Arial", 16);
- EXPECT_EQ("arial", base::ToLowerASCII(arial.GetActualFontNameForTesting()))
+ Font arial(kTestFontName, 16);
+ EXPECT_EQ(base::ToLowerASCII(kTestFontName),
+ base::ToLowerASCII(arial.GetActualFontNameForTesting()))
<< "********\n"
<< "Your test environment seems to be missing Arial font, which is "
<< "needed for unittests. Check if Arial font is installed.\n"
@@ -169,7 +172,7 @@ TEST_F(FontTest, MAYBE_GetActualFontNameForTesting) {
#define MAYBE_DeriveFont DeriveFont
#endif
TEST_F(FontTest, MAYBE_DeriveFont) {
- Font cf("Arial", 8);
+ Font cf(kTestFontName, 8);
const int kSizeDelta = 2;
Font cf_underlined =
cf.Derive(0, cf.GetStyle() | gfx::Font::UNDERLINE, cf.GetWeight());
@@ -183,7 +186,7 @@ TEST_F(FontTest, MAYBE_DeriveFont) {
#if defined(OS_WIN)
TEST_F(FontTest, DeriveResizesIfSizeTooSmall) {
- Font cf("Arial", 8);
+ Font cf(kTestFontName, 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
@@ -192,7 +195,7 @@ TEST_F(FontTest, DeriveResizesIfSizeTooSmall) {
}
TEST_F(FontTest, DeriveKeepsOriginalSizeIfHeightOk) {
- Font cf("Arial", 8);
+ Font cf(kTestFontName, 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
diff --git a/chromium/ui/gfx/gpu_fence_handle.h b/chromium/ui/gfx/gpu_fence_handle.h
index 093626c89f7..29a9c097a40 100644
--- a/chromium/ui/gfx/gpu_fence_handle.h
+++ b/chromium/ui/gfx/gpu_fence_handle.h
@@ -5,7 +5,6 @@
#ifndef UI_GFX_GPU_FENCE_HANDLE_H_
#define UI_GFX_GPU_FENCE_HANDLE_H_
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
diff --git a/chromium/ui/gfx/image/canvas_image_source.cc b/chromium/ui/gfx/image/canvas_image_source.cc
index 728977c0ef3..4d68d315bde 100644
--- a/chromium/ui/gfx/image/canvas_image_source.cc
+++ b/chromium/ui/gfx/image/canvas_image_source.cc
@@ -6,22 +6,52 @@
#include "base/logging.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/image/image_skia.h"
namespace gfx {
+namespace {
+
+class PaddedImageSource : public CanvasImageSource {
+ public:
+ PaddedImageSource(const ImageSkia& image, const Insets& insets)
+ : CanvasImageSource(Size(image.width() + insets.width(),
+ image.height() + insets.height()),
+ false),
+ image_(image),
+ insets_(insets) {}
+
+ // CanvasImageSource:
+ void Draw(Canvas* canvas) override {
+ canvas->DrawImageInt(image_, insets_.left(), insets_.top());
+ }
+
+ private:
+ const ImageSkia image_;
+ const Insets insets_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaddedImageSource);
+};
+
+} // namespace
+
////////////////////////////////////////////////////////////////////////////////
// CanvasImageSource
-CanvasImageSource::CanvasImageSource(const gfx::Size& size, bool is_opaque)
- : size_(size),
- is_opaque_(is_opaque) {
+// static
+ImageSkia CanvasImageSource::CreatePadded(const ImageSkia& image,
+ const Insets& insets) {
+ return MakeImageSkia<PaddedImageSource>(image, insets);
}
-gfx::ImageSkiaRep CanvasImageSource::GetImageForScale(float scale) {
- gfx::Canvas canvas(size_, scale, is_opaque_);
+CanvasImageSource::CanvasImageSource(const Size& size, bool is_opaque)
+ : size_(size), is_opaque_(is_opaque) {}
+
+ImageSkiaRep CanvasImageSource::GetImageForScale(float scale) {
+ Canvas canvas(size_, scale, is_opaque_);
Draw(&canvas);
- return gfx::ImageSkiaRep(canvas.GetBitmap(), scale);
+ return ImageSkiaRep(canvas.GetBitmap(), scale);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/image/canvas_image_source.h b/chromium/ui/gfx/image/canvas_image_source.h
index 558648d3ce7..20e13accfa8 100644
--- a/chromium/ui/gfx/image/canvas_image_source.h
+++ b/chromium/ui/gfx/image/canvas_image_source.h
@@ -9,7 +9,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/image/image_skia.h"
@@ -18,37 +17,41 @@
namespace gfx {
class Canvas;
class ImageSkiaRep;
+class Insets;
-// CanvasImageSource is useful if you need to generate an image for
-// a scale factor using gfx::Canvas. It creates a new Canvas
-// with target scale factor and generates ImageSkiaRep when drawing is
-// completed.
-class GFX_EXPORT CanvasImageSource : public gfx::ImageSkiaSource {
+// CanvasImageSource is useful if you need to generate an image for a scale
+// factor using Canvas. It creates a new Canvas with target scale factor and
+// generates ImageSkiaRep when drawing is completed.
+class GFX_EXPORT CanvasImageSource : public ImageSkiaSource {
public:
// Factory function to create an ImageSkia from a CanvasImageSource. Example:
- // gfx::ImageSkia my_image =
+ // ImageSkia my_image =
// CanvasImageSource::MakeImageSkia<MySource>(param1, param2);
template <typename T, typename... Args>
static ImageSkia MakeImageSkia(Args&&... args) {
auto source = std::make_unique<T>(std::forward<Args>(args)...);
- gfx::Size size = source->size();
- return gfx::ImageSkia(std::move(source), size);
+ Size size = source->size();
+ return ImageSkia(std::move(source), size);
}
- CanvasImageSource(const gfx::Size& size, bool is_opaque);
+ // Creates a Image containing |image| with transparent padding around the
+ // edges as specified by |insets|.
+ static ImageSkia CreatePadded(const ImageSkia& image, const Insets& insets);
+
+ CanvasImageSource(const Size& size, bool is_opaque);
~CanvasImageSource() override {}
// Called when a new image needs to be drawn for a scale factor.
- virtual void Draw(gfx::Canvas* canvas) = 0;
+ virtual void Draw(Canvas* canvas) = 0;
// Returns the size of images in DIP that this source will generate.
- const gfx::Size& size() const { return size_; };
+ const Size& size() const { return size_; };
- // Overridden from gfx::ImageSkiaSource.
- gfx::ImageSkiaRep GetImageForScale(float scale) override;
+ // Overridden from ImageSkiaSource.
+ ImageSkiaRep GetImageForScale(float scale) override;
protected:
- const gfx::Size size_;
+ const Size size_;
const bool is_opaque_;
DISALLOW_COPY_AND_ASSIGN(CanvasImageSource);
};
diff --git a/chromium/ui/gfx/image/mojo/image_traits_unittest.cc b/chromium/ui/gfx/image/mojo/image_traits_unittest.cc
index bca8f37c04f..de87d867765 100644
--- a/chromium/ui/gfx/image/mojo/image_traits_unittest.cc
+++ b/chromium/ui/gfx/image/mojo/image_traits_unittest.cc
@@ -6,7 +6,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/gfx/interpolated_transform.cc b/chromium/ui/gfx/interpolated_transform.cc
index f5bb4f40569..5771a1e3e95 100644
--- a/chromium/ui/gfx/interpolated_transform.cc
+++ b/chromium/ui/gfx/interpolated_transform.cc
@@ -6,7 +6,6 @@
#include <cmath>
-#include "base/memory/ptr_util.h"
#include "base/logging.h"
#include "ui/gfx/animation/tween.h"
diff --git a/chromium/ui/gfx/interpolated_transform_unittest.cc b/chromium/ui/gfx/interpolated_transform_unittest.cc
index 40ed89a74f3..6856c2c057b 100644
--- a/chromium/ui/gfx/interpolated_transform_unittest.cc
+++ b/chromium/ui/gfx/interpolated_transform_unittest.cc
@@ -4,7 +4,6 @@
#include "ui/gfx/interpolated_transform.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
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 a9fd8622ef5..ea246a986e8 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -63,7 +63,9 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
format == gfx::BufferFormat::YVU_420;
case gfx::BufferUsage::SCANOUT:
return format == gfx::BufferFormat::BGRX_8888 ||
- format == gfx::BufferFormat::RGBX_8888;
+ format == gfx::BufferFormat::RGBX_8888 ||
+ format == gfx::BufferFormat::RGBA_8888 ||
+ format == gfx::BufferFormat::BGRA_8888;
case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
return
#if defined(ARCH_CPU_X86_FAMILY)
diff --git a/chromium/ui/gfx/linux/native_pixmap_dmabuf.cc b/chromium/ui/gfx/linux/native_pixmap_dmabuf.cc
index 8502ccb227e..e03e8f615a8 100644
--- a/chromium/ui/gfx/linux/native_pixmap_dmabuf.cc
+++ b/chromium/ui/gfx/linux/native_pixmap_dmabuf.cc
@@ -75,7 +75,8 @@ bool NativePixmapDmaBuf::ScheduleOverlayPlane(
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
diff --git a/chromium/ui/gfx/linux/native_pixmap_dmabuf.h b/chromium/ui/gfx/linux/native_pixmap_dmabuf.h
index d01868ad2a2..f32389e7318 100644
--- a/chromium/ui/gfx/linux/native_pixmap_dmabuf.h
+++ b/chromium/ui/gfx/linux/native_pixmap_dmabuf.h
@@ -42,7 +42,8 @@ class GFX_EXPORT NativePixmapDmaBuf : public gfx::NativePixmap {
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
gfx::NativePixmapHandle ExportHandle() override;
protected:
diff --git a/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
index b20492cf197..d67d1b60865 100644
--- a/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
+++ b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
@@ -5,10 +5,8 @@
#ifndef UI_GFX_MAC_SCOPED_COCOA_DISABLE_SCREEN_UPDATES_H_
#define UI_GFX_MAC_SCOPED_COCOA_DISABLE_SCREEN_UPDATES_H_
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/mac_util.h"
#include "base/macros.h"
+#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -17,25 +15,10 @@ namespace gfx {
// can be nested, and there is a time-maximum (about 1 second) after which
// Cocoa will automatically re-enable updating. This class doesn't attempt to
// overrule that.
-class ScopedCocoaDisableScreenUpdates {
+class GFX_EXPORT ScopedCocoaDisableScreenUpdates {
public:
- 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();
- }
- }
- ~ScopedCocoaDisableScreenUpdates() {
- if (base::mac::IsAtLeastOS10_11()) {
- [NSAnimationContext endGrouping];
- } else {
- NSEnableScreenUpdates();
- }
- }
+ ScopedCocoaDisableScreenUpdates();
+ ~ScopedCocoaDisableScreenUpdates();
private:
DISALLOW_COPY_AND_ASSIGN(ScopedCocoaDisableScreenUpdates);
diff --git a/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
new file mode 100644
index 00000000000..981a6eff43d
--- /dev/null
+++ b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
@@ -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/gfx/mac/scoped_cocoa_disable_screen_updates.h"
+
+#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();
+ }
+}
+
+ScopedCocoaDisableScreenUpdates::~ScopedCocoaDisableScreenUpdates() {
+ if (base::mac::IsAtLeastOS10_11()) {
+ [NSAnimationContext endGrouping];
+ } else {
+ NSEnableScreenUpdates();
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/native_pixmap.h b/chromium/ui/gfx/native_pixmap.h
index c168001700c..abf442c6dcc 100644
--- a/chromium/ui/gfx/native_pixmap.h
+++ b/chromium/ui/gfx/native_pixmap.h
@@ -52,11 +52,14 @@ class NativePixmap : public base::RefCountedThreadSafe<NativePixmap> {
// |crop_rect| specifies the region within the buffer to be placed
// inside |display_bounds|. This is specified in texture coordinates, in the
// range of [0,1].
+ // |enable_blend| specifies if the plane should be alpha blended, with premul
+ // apha, when scanned out.
virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) = 0;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) = 0;
// Export the buffer for sharing across processes.
// Any file descriptors in the exported handle are owned by the caller.
diff --git a/chromium/ui/gfx/paint_vector_icon.cc b/chromium/ui/gfx/paint_vector_icon.cc
index b9832d0f231..d2968ffe32f 100644
--- a/chromium/ui/gfx/paint_vector_icon.cc
+++ b/chromium/ui/gfx/paint_vector_icon.cc
@@ -10,7 +10,6 @@
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/trace_event/trace_event.h"
@@ -42,12 +41,14 @@ struct CompareIconDescription {
// Helper that simplifies iterating over a sequence of PathElements.
class PathParser {
public:
- PathParser(const PathElement* path_elements)
- : path_elements_(path_elements) {}
+ PathParser(const PathElement* path_elements, size_t path_size)
+ : path_elements_(path_elements), path_size_(path_size) {}
~PathParser() {}
void Advance() { command_index_ += GetArgumentCount() + 1; }
+ bool HasCommandsRemaining() const { return command_index_ < path_size_; }
+
CommandType CurrentCommand() const {
return path_elements_[command_index_].command;
}
@@ -103,7 +104,6 @@ class PathParser {
case FLIPS_IN_RTL:
case TRANSITION_FROM:
case TRANSITION_TO:
- case END:
return 0;
}
@@ -112,7 +112,8 @@ class PathParser {
}
const PathElement* path_elements_;
- int command_index_ = 0;
+ size_t path_size_;
+ size_t command_index_ = 0;
DISALLOW_COPY_AND_ASSIGN(PathParser);
};
@@ -149,7 +150,6 @@ CommandType CommandFromString(const std::string& source) {
RETURN_IF_IS(CLIP);
RETURN_IF_IS(DISABLE_AA);
RETURN_IF_IS(FLIPS_IN_RTL);
- RETURN_IF_IS(END);
#undef RETURN_IF_IS
NOTREACHED() << "Unrecognized command: " << source;
@@ -175,6 +175,7 @@ std::vector<PathElement> PathFromSource(const std::string& source) {
void PaintPath(Canvas* canvas,
const PathElement* path_elements,
+ size_t path_size,
int dip_size,
SkColor color,
const base::TimeDelta& elapsed_time) {
@@ -188,8 +189,8 @@ void PaintPath(Canvas* canvas,
bool flips_in_rtl = false;
CommandType previous_command_type = NEW_PATH;
- for (PathParser parser(path_elements); parser.CurrentCommand() != END;
- parser.Advance()) {
+ for (PathParser parser(path_elements, path_size);
+ parser.HasCommandsRemaining(); parser.Advance()) {
auto arg = [&parser](int i) { return parser.GetArgument(i); };
const CommandType command_type = parser.CurrentCommand();
auto start_new_path = [&paths]() {
@@ -430,10 +431,6 @@ void PaintPath(Canvas* canvas,
flags_array.pop_back();
break;
}
-
- case END:
- NOTREACHED();
- break;
}
previous_command_type = command_type;
@@ -481,7 +478,7 @@ class VectorIconSource : public CanvasImageSource {
if (!data_.badge_icon.is_empty())
PaintVectorIcon(canvas, data_.badge_icon, size_.width(), data_.color);
} else {
- PaintPath(canvas, path_.data(), size_.width(), data_.color,
+ PaintPath(canvas, path_.data(), path_.size(), size_.width(), data_.color,
base::TimeDelta());
}
}
@@ -540,7 +537,7 @@ IconDescription::IconDescription(const VectorIcon& icon,
// If an icon has a .1x.icon version, it should only be rendered at the size
// specified in that definition.
- if (icon.path_1x)
+ if (icon.rep_1x)
DCHECK_EQ(this->dip_size, GetDefaultSizeOfVectorIcon(icon));
}
@@ -562,17 +559,13 @@ void PaintVectorIcon(Canvas* canvas,
SkColor color,
const base::TimeDelta& elapsed_time) {
DCHECK(!icon.is_empty());
- if (icon.path) {
- DCHECK(icon.path_size > 0);
- DCHECK_EQ(END, icon.path[icon.path_size - 1].command) << icon.name;
- }
- if (icon.path_1x) {
- DCHECK(icon.path_1x_size > 0);
- DCHECK_EQ(END, icon.path_1x[icon.path_1x_size - 1].command) << icon.name;
- }
- const PathElement* path =
- (canvas->image_scale() == 1.f && icon.path_1x) ? icon.path_1x : icon.path;
- PaintPath(canvas, path, dip_size, color, elapsed_time);
+ if (icon.rep)
+ DCHECK(icon.rep->path_size > 0);
+ if (icon.rep_1x)
+ DCHECK(icon.rep_1x->path_size > 0);
+ const VectorIconRep* rep =
+ (canvas->image_scale() == 1.f && icon.rep_1x) ? icon.rep_1x : icon.rep;
+ PaintPath(canvas, rep->path, rep->path_size, dip_size, color, elapsed_time);
}
ImageSkia CreateVectorIcon(const IconDescription& params) {
@@ -609,15 +602,16 @@ ImageSkia CreateVectorIconFromSource(const std::string& source,
}
int GetDefaultSizeOfVectorIcon(const VectorIcon& icon) {
- const PathElement* one_x_path = icon.path_1x ? icon.path_1x : icon.path;
+ const PathElement* one_x_path =
+ icon.rep_1x ? icon.rep_1x->path : icon.rep->path;
return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg
: kReferenceSizeDip;
}
base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon) {
base::TimeDelta last_motion;
- for (PathParser parser(icon.path); parser.CurrentCommand() != END;
- parser.Advance()) {
+ for (PathParser parser(icon.rep->path, icon.rep->path_size);
+ parser.HasCommandsRemaining(); parser.Advance()) {
if (parser.CurrentCommand() != TRANSITION_END)
continue;
diff --git a/chromium/ui/gfx/paint_vector_icon_unittest.cc b/chromium/ui/gfx/paint_vector_icon_unittest.cc
index 6570dc52d8b..1188c35e23f 100644
--- a/chromium/ui/gfx/paint_vector_icon_unittest.cc
+++ b/chromium/ui/gfx/paint_vector_icon_unittest.cc
@@ -43,15 +43,11 @@ TEST(VectorIconTest, RelativeMoveToAfterClose) {
Canvas canvas(recorder.beginRecording(100, 100), 1.0f);
const PathElement elements[] = {
- MOVE_TO, 4, 5,
- LINE_TO, 10, 11,
- CLOSE,
+ MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
// This move should use (4, 5) as the start point rather than (10, 11).
- R_MOVE_TO, 20, 21,
- R_LINE_TO, 50, 51,
- END,
- };
- const VectorIcon icon = {elements, arraysize(elements)};
+ R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
+ const VectorIconRep icon_rep = {elements, arraysize(elements)};
+ const VectorIcon icon = {&icon_rep};
PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture();
@@ -78,17 +74,21 @@ TEST(VectorIconTest, FlipsInRtl) {
// Create a 20x20 square icon which has FLIPS_IN_RTL, and CANVAS_DIMENSIONS
// are twice as large as |canvas|.
- const PathElement elements[] = {
- CANVAS_DIMENSIONS, 2 * canvas_size,
- FLIPS_IN_RTL,
- MOVE_TO, 10, 10,
- R_H_LINE_TO, 20,
- R_V_LINE_TO, 20,
- R_H_LINE_TO, -20,
- CLOSE,
- END,
- };
- const VectorIcon icon = {elements, arraysize(elements)};
+ const PathElement elements[] = {CANVAS_DIMENSIONS,
+ 2 * canvas_size,
+ FLIPS_IN_RTL,
+ MOVE_TO,
+ 10,
+ 10,
+ R_H_LINE_TO,
+ 20,
+ R_V_LINE_TO,
+ 20,
+ R_H_LINE_TO,
+ -20,
+ CLOSE};
+ const VectorIconRep icon_rep = {elements, arraysize(elements)};
+ const VectorIcon icon = {&icon_rep};
PaintVectorIcon(&canvas, icon, canvas_size, color);
// Count the number of pixels in the canvas.
diff --git a/chromium/ui/gfx/platform_font_linux_unittest.cc b/chromium/ui/gfx/platform_font_linux_unittest.cc
index f677ba4dda9..4d73bee9bf6 100644
--- a/chromium/ui/gfx/platform_font_linux_unittest.cc
+++ b/chromium/ui/gfx/platform_font_linux_unittest.cc
@@ -13,7 +13,6 @@
#include "ui/gfx/font.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/linux_font_delegate.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
namespace gfx {
@@ -62,7 +61,6 @@ class TestFontDelegate : public LinuxFontDelegate {
class PlatformFontLinuxTest : public testing::Test {
public:
PlatformFontLinuxTest() {
- SetUpFontconfig();
original_font_delegate_ = LinuxFontDelegate::instance();
LinuxFontDelegate::SetInstance(&test_font_delegate_);
}
@@ -71,7 +69,6 @@ class PlatformFontLinuxTest : public testing::Test {
LinuxFontDelegate::SetInstance(
const_cast<LinuxFontDelegate*>(original_font_delegate_));
PlatformFontLinux::ReloadDefaultFont();
- TearDownFontconfig();
}
protected:
@@ -87,13 +84,10 @@ class PlatformFontLinuxTest : public testing::Test {
// Test that PlatformFontLinux's default constructor initializes the instance
// with the correct parameters.
TEST_F(PlatformFontLinuxTest, DefaultFont) {
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
- ASSERT_TRUE(LoadSystemFontIntoFontconfig("times_new_roman.ttf"));
-
#if defined(OS_CHROMEOS)
- PlatformFontLinux::SetDefaultFontDescription("Arial,Times New Roman,13px");
+ PlatformFontLinux::SetDefaultFontDescription("Arimo,Tinos,13px");
#else
- test_font_delegate_.set_family("Arial");
+ test_font_delegate_.set_family("Arimo");
test_font_delegate_.set_size_pixels(13);
test_font_delegate_.set_style(Font::NORMAL);
FontRenderParams params;
@@ -102,7 +96,7 @@ TEST_F(PlatformFontLinuxTest, DefaultFont) {
test_font_delegate_.set_params(params);
#endif
scoped_refptr<gfx::PlatformFontLinux> font(new gfx::PlatformFontLinux());
- EXPECT_EQ("Arial", font->GetFontName());
+ EXPECT_EQ("Arimo", font->GetFontName());
EXPECT_EQ(13, font->GetFontSize());
EXPECT_EQ(gfx::Font::NORMAL, font->GetStyle());
#if !defined(OS_CHROMEOS)
@@ -114,16 +108,16 @@ TEST_F(PlatformFontLinuxTest, DefaultFont) {
// Drop the old default font and check that new settings are loaded.
#if defined(OS_CHROMEOS)
PlatformFontLinux::SetDefaultFontDescription(
- "Times New Roman,Arial,Bold Italic 15px");
+ "Tinos,Arimo,Bold Italic 15px");
#else
- test_font_delegate_.set_family("Times New Roman");
+ test_font_delegate_.set_family("Tinos");
test_font_delegate_.set_size_pixels(15);
test_font_delegate_.set_style(gfx::Font::ITALIC);
test_font_delegate_.set_weight(gfx::Font::Weight::BOLD);
#endif
PlatformFontLinux::ReloadDefaultFont();
scoped_refptr<gfx::PlatformFontLinux> font2(new gfx::PlatformFontLinux());
- EXPECT_EQ("Times New Roman", font2->GetFontName());
+ EXPECT_EQ("Tinos", font2->GetFontName());
EXPECT_EQ(15, font2->GetFontSize());
EXPECT_NE(font2->GetStyle() & Font::ITALIC, 0);
EXPECT_EQ(gfx::Font::Weight::BOLD, font2->GetWeight());
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index 3d706df56ee..39702db77da 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -13,7 +13,6 @@
#include "base/feature_list.h"
#include "base/i18n/break_iterator.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/numerics/ranges.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -278,14 +277,17 @@ void SkiaTextRenderer::DrawStrike(int x,
StyleIterator::StyleIterator(const BreakList<SkColor>& colors,
const BreakList<BaselineStyle>& baselines,
+ const BreakList<int>& font_size_overrides,
const BreakList<Font::Weight>& weights,
const std::vector<BreakList<bool>>& styles)
: colors_(colors),
baselines_(baselines),
+ font_size_overrides_(font_size_overrides),
weights_(weights),
styles_(styles) {
color_ = colors_.breaks().begin();
baseline_ = baselines_.breaks().begin();
+ font_size_override_ = font_size_overrides_.breaks().begin();
weight_ = weights_.breaks().begin();
for (size_t i = 0; i < styles_.size(); ++i)
style_.push_back(styles_[i].breaks().begin());
@@ -296,6 +298,7 @@ StyleIterator::~StyleIterator() {}
Range StyleIterator::GetRange() const {
Range range(colors_.GetRange(color_));
range = range.Intersect(baselines_.GetRange(baseline_));
+ range = range.Intersect(font_size_overrides_.GetRange(font_size_override_));
range = range.Intersect(weights_.GetRange(weight_));
for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
range = range.Intersect(styles_[i].GetRange(style_[i]));
@@ -305,6 +308,7 @@ Range StyleIterator::GetRange() const {
void StyleIterator::UpdatePosition(size_t position) {
color_ = colors_.GetBreak(position);
baseline_ = baselines_.GetBreak(position);
+ font_size_override_ = font_size_overrides_.GetBreak(position);
weight_ = weights_.GetBreak(position);
for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
style_[i] = styles_[i].GetBreak(position);
@@ -380,6 +384,7 @@ std::unique_ptr<RenderText> RenderText::CreateInstanceOfSameStyle(
render_text->set_truncate_length(truncate_length_);
render_text->styles_ = styles_;
render_text->baselines_ = baselines_;
+ render_text->font_size_overrides_ = font_size_overrides_;
render_text->colors_ = colors_;
render_text->weights_ = weights_;
return render_text;
@@ -396,6 +401,7 @@ void RenderText::SetText(const base::string16& text) {
// the first style to the whole text instead.
colors_.SetValue(colors_.breaks().begin()->second);
baselines_.SetValue(baselines_.breaks().begin()->second);
+ font_size_overrides_.SetValue(font_size_overrides_.breaks().begin()->second);
weights_.SetValue(weights_.breaks().begin()->second);
for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
styles_[style].SetValue(styles_[style].breaks().begin()->second);
@@ -709,6 +715,11 @@ void RenderText::ApplyBaselineStyle(BaselineStyle value, const Range& range) {
baselines_.ApplyValue(value, range);
}
+void RenderText::ApplyFontSizeOverride(int font_size_override,
+ const Range& range) {
+ font_size_overrides_.ApplyValue(font_size_override, range);
+}
+
void RenderText::SetStyle(TextStyle style, bool value) {
styles_[style].SetValue(value);
@@ -973,9 +984,9 @@ Vector2d RenderText::GetLineOffset(size_t line_number) {
return offset;
}
-bool RenderText::GetDecoratedWordAtPoint(const Point& point,
- DecoratedText* decorated_word,
- Point* baseline_point) {
+bool RenderText::GetWordLookupDataAtPoint(const Point& point,
+ DecoratedText* decorated_word,
+ Point* baseline_point) {
if (obscured())
return false;
@@ -990,9 +1001,16 @@ bool RenderText::GetDecoratedWordAtPoint(const Point& point,
DCHECK(!word_range.is_reversed());
DCHECK(!word_range.is_empty());
- const std::vector<Rect> word_bounds = GetSubstringBounds(word_range);
- if (word_bounds.empty() ||
- !GetDecoratedTextForRange(word_range, decorated_word)) {
+ return GetLookupDataForRange(word_range, decorated_word, baseline_point);
+}
+
+bool RenderText::GetLookupDataForRange(const Range& range,
+ DecoratedText* decorated_text,
+ Point* baseline_point) {
+ EnsureLayout();
+
+ const std::vector<Rect> word_bounds = GetSubstringBounds(range);
+ if (word_bounds.empty() || !GetDecoratedTextForRange(range, decorated_text)) {
return false;
}
@@ -1027,6 +1045,7 @@ RenderText::RenderText()
composition_range_(Range::InvalidRange()),
colors_(kDefaultColor),
baselines_(NORMAL_BASELINE),
+ font_size_overrides_(0),
weights_(Font::Weight::NORMAL),
styles_(NUM_TEXT_STYLES),
composition_and_selection_styles_applied_(false),
@@ -1357,6 +1376,7 @@ void RenderText::UpdateStyleLengths() {
const size_t text_length = text_.length();
colors_.SetMax(text_length);
baselines_.SetMax(text_length);
+ font_size_overrides_.SetMax(text_length);
weights_.SetMax(text_length);
for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
styles_[style].SetMax(text_length);
@@ -1561,6 +1581,7 @@ base::string16 RenderText::Elide(const base::string16& text,
for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
RestoreBreakList(render_text.get(), &render_text->styles_[style]);
RestoreBreakList(render_text.get(), &render_text->baselines_);
+ RestoreBreakList(render_text.get(), &render_text->font_size_overrides_);
render_text->weights_ = weights_;
RestoreBreakList(render_text.get(), &render_text->weights_);
diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h
index 47fa4c605ce..4cc2bdc85fe 100644
--- a/chromium/ui/gfx/render_text.h
+++ b/chromium/ui/gfx/render_text.h
@@ -88,6 +88,7 @@ class StyleIterator {
public:
StyleIterator(const BreakList<SkColor>& colors,
const BreakList<BaselineStyle>& baselines,
+ const BreakList<int>& font_size_overrides,
const BreakList<Font::Weight>& weights,
const std::vector<BreakList<bool>>& styles);
~StyleIterator();
@@ -95,6 +96,7 @@ class StyleIterator {
// Get the colors and styles at the current iterator position.
SkColor color() const { return color_->second; }
BaselineStyle baseline() const { return baseline_->second; }
+ int font_size_override() const { return font_size_override_->second; }
bool style(TextStyle s) const { return style_[s]->second; }
Font::Weight weight() const { return weight_->second; }
@@ -107,11 +109,13 @@ class StyleIterator {
private:
BreakList<SkColor> colors_;
BreakList<BaselineStyle> baselines_;
+ BreakList<int> font_size_overrides_;
BreakList<Font::Weight> weights_;
std::vector<BreakList<bool> > styles_;
BreakList<SkColor>::const_iterator color_;
BreakList<BaselineStyle>::const_iterator baseline_;
+ BreakList<int>::const_iterator font_size_override_;
BreakList<Font::Weight>::const_iterator weight_;
std::vector<BreakList<bool>::const_iterator> style_;
@@ -365,11 +369,17 @@ class GFX_EXPORT RenderText {
void SetColor(SkColor value);
void ApplyColor(SkColor value, const Range& range);
+ // DEPRECATED.
// Set the baseline style over the entire text or a logical character range.
// The |range| should be valid, non-reversed, and within [0, text().length()].
+ // TODO(tapted): Remove this. The only client is moving to
+ // ApplyFontSizeOverride.
void SetBaselineStyle(BaselineStyle value);
void ApplyBaselineStyle(BaselineStyle value, const Range& range);
+ // Alters the font size in |range|.
+ void ApplyFontSizeOverride(int font_size_override, const Range& range);
+
// Set various text styles over the entire text or a logical character range.
// The respective |style| is applied if |value| is true, or removed if false.
// The |range| should be valid, non-reversed, and within [0, text().length()].
@@ -507,9 +517,19 @@ class GFX_EXPORT RenderText {
// at the point, returns a nearby word. |baseline_point| should correspond to
// the baseline point of the leftmost glyph of the |word| in the view's
// coordinates. Returns false, if no word can be retrieved.
- bool GetDecoratedWordAtPoint(const Point& point,
- DecoratedText* decorated_word,
- Point* baseline_point);
+ bool GetWordLookupDataAtPoint(const Point& point,
+ DecoratedText* decorated_word,
+ Point* baseline_point);
+
+ // Retrieves the text at |range| along with its styling information.
+ // |baseline_point| should correspond to the baseline point of
+ // the leftmost glyph of the text in the view's coordinates. If the text
+ // spans multiple lines, |baseline_point| will correspond with the leftmost
+ // glyph on the first line in the range. Returns false, if no text can be
+ // retrieved.
+ bool GetLookupDataForRange(const Range& range,
+ DecoratedText* decorated_text,
+ Point* baseline_point);
// Retrieves the text in the given |range|.
base::string16 GetTextFromRange(const Range& range) const;
@@ -527,6 +547,9 @@ class GFX_EXPORT RenderText {
const BreakList<SkColor>& colors() const { return colors_; }
const BreakList<BaselineStyle>& baselines() const { return baselines_; }
+ const BreakList<int>& font_size_overrides() const {
+ return font_size_overrides_;
+ }
const BreakList<Font::Weight>& weights() const { return weights_; }
const std::vector<BreakList<bool> >& styles() const { return styles_; }
SkScalar strike_thickness_factor() const { return strike_thickness_factor_; }
@@ -767,6 +790,7 @@ class GFX_EXPORT RenderText {
// TODO(msw): Expand to support cursor, selection, background, etc. colors.
BreakList<SkColor> colors_;
BreakList<BaselineStyle> baselines_;
+ BreakList<int> font_size_overrides_;
BreakList<Font::Weight> weights_;
std::vector<BreakList<bool> > styles_;
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
index 9178adbe330..838ee6215ea 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.cc
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -1415,7 +1415,8 @@ void RenderTextHarfBuzz::ItemizeTextToRuns(
DCHECK_LE(text.size(), baselines().max());
for (const BreakList<bool>& style : styles())
DCHECK_LE(text.size(), style.max());
- internal::StyleIterator style(empty_colors, baselines(), weights(), styles());
+ internal::StyleIterator style(empty_colors, baselines(),
+ font_size_overrides(), weights(), styles());
for (size_t run_break = 0; run_break < text.length();) {
auto run = std::make_unique<internal::TextRunHarfBuzz>(
@@ -1423,6 +1424,7 @@ void RenderTextHarfBuzz::ItemizeTextToRuns(
run->range.set_start(run_break);
run->italic = style.style(ITALIC);
run->baseline_type = style.baseline();
+ run->font_size = style.font_size_override();
run->strike = style.style(STRIKE);
run->underline = style.style(UNDERLINE);
run->heavy_underline = style.style(HEAVY_UNDERLINE);
@@ -1496,7 +1498,8 @@ void RenderTextHarfBuzz::ShapeRun(const base::string16& text,
internal::TextRunHarfBuzz* run) {
const Font& primary_font = font_list().GetPrimaryFont();
const std::string primary_family = primary_font.GetFontName();
- run->font_size = primary_font.GetFontSize();
+ if (run->font_size == 0)
+ run->font_size = primary_font.GetFontSize();
run->baseline_offset = 0;
if (run->baseline_type != NORMAL_BASELINE) {
// Calculate a slightly smaller font. The ratio here is somewhat arbitrary.
diff --git a/chromium/ui/gfx/render_text_mac.mm b/chromium/ui/gfx/render_text_mac.mm
index bf162b3ddfc..41139a49c0f 100644
--- a/chromium/ui/gfx/render_text_mac.mm
+++ b/chromium/ui/gfx/render_text_mac.mm
@@ -349,7 +349,8 @@ base::ScopedCFTypeRef<CFMutableArrayRef> RenderTextMac::ApplyStyles(
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
// https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CoreText_StringAttributes_Ref/Reference/reference.html
- internal::StyleIterator style(colors(), baselines(), weights(), styles());
+ internal::StyleIterator style(colors(), baselines(), font_size_overrides(),
+ weights(), styles());
const size_t layout_text_length = CFAttributedStringGetLength(attr_string);
for (size_t i = 0, end = 0; i < layout_text_length; i = end) {
end = TextIndexToGivenTextIndex(text, style.GetRange().end());
diff --git a/chromium/ui/gfx/render_text_test_api.h b/chromium/ui/gfx/render_text_test_api.h
index dbb6c4436e6..00981c3cd76 100644
--- a/chromium/ui/gfx/render_text_test_api.h
+++ b/chromium/ui/gfx/render_text_test_api.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef UI_GFX_RENDER_TEXT_TEST_API_H_
+#define UI_GFX_RENDER_TEXT_TEST_API_H_
+
#include "base/macros.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -37,6 +40,10 @@ class RenderTextTestApi {
return render_text_->baselines();
}
+ const BreakList<int>& font_size_overrides() const {
+ return render_text_->font_size_overrides();
+ }
+
const BreakList<Font::Weight>& weights() const {
return render_text_->weights();
}
@@ -85,3 +92,5 @@ class RenderTextTestApi {
} // namespace test
} // namespace gfx
+
+#endif // UI_GFX_RENDER_TEXT_TEST_API_H_
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index 5a47cee1adf..b1fb9063920 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -15,7 +15,6 @@
#include "base/format_macros.h"
#include "base/i18n/break_iterator.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -597,6 +596,7 @@ TEST_P(RenderTextTest, DefaultStyles) {
for (size_t i = 0; i < arraysize(cases); ++i) {
EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(SK_ColorBLACK));
EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(NORMAL_BASELINE));
+ EXPECT_TRUE(test_api()->font_size_overrides().EqualsValueForTesting(0));
for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
EXPECT_TRUE(test_api()->styles()[style].EqualsValueForTesting(false));
render_text->SetText(UTF8ToUTF16(cases[i]));
@@ -632,32 +632,27 @@ TEST_P(RenderTextTest, ApplyStyles) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("012345678"));
+ constexpr int kTestFontSizeOverride = 20;
+
// Apply a ranged color and style and check the resulting breaks.
render_text->ApplyColor(SK_ColorRED, Range(1, 4));
render_text->ApplyBaselineStyle(SUPERIOR, Range(2, 4));
render_text->ApplyWeight(Font::Weight::BOLD, Range(2, 5));
- std::vector<std::pair<size_t, SkColor> > expected_color;
- expected_color.push_back(std::pair<size_t, SkColor>(0, SK_ColorBLACK));
- expected_color.push_back(std::pair<size_t, SkColor>(1, SK_ColorRED));
- expected_color.push_back(std::pair<size_t, SkColor>(4, SK_ColorBLACK));
- EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color));
- std::vector<std::pair<size_t, BaselineStyle>> expected_baseline_style;
- expected_baseline_style.push_back(
- std::pair<size_t, BaselineStyle>(0, NORMAL_BASELINE));
- expected_baseline_style.push_back(
- std::pair<size_t, BaselineStyle>(2, SUPERIOR));
- expected_baseline_style.push_back(
- std::pair<size_t, BaselineStyle>(4, NORMAL_BASELINE));
+ render_text->ApplyFontSizeOverride(kTestFontSizeOverride, Range(5, 7));
+
+ EXPECT_TRUE(test_api()->colors().EqualsForTesting(
+ {{0, SK_ColorBLACK}, {1, SK_ColorRED}, {4, SK_ColorBLACK}}));
+
+ EXPECT_TRUE(test_api()->baselines().EqualsForTesting(
+ {{0, NORMAL_BASELINE}, {2, SUPERIOR}, {4, NORMAL_BASELINE}}));
+
+ EXPECT_TRUE(test_api()->font_size_overrides().EqualsForTesting(
+ {{0, 0}, {5, kTestFontSizeOverride}, {7, 0}}));
+
EXPECT_TRUE(
- test_api()->baselines().EqualsForTesting(expected_baseline_style));
- std::vector<std::pair<size_t, Font::Weight>> expected_weight;
- expected_weight.push_back(
- std::pair<size_t, Font::Weight>(0, Font::Weight::NORMAL));
- expected_weight.push_back(
- std::pair<size_t, Font::Weight>(2, Font::Weight::BOLD));
- expected_weight.push_back(
- std::pair<size_t, Font::Weight>(5, Font::Weight::NORMAL));
- EXPECT_TRUE(test_api()->weights().EqualsForTesting(expected_weight));
+ test_api()->weights().EqualsForTesting({{0, Font::Weight::NORMAL},
+ {2, Font::Weight::BOLD},
+ {5, Font::Weight::NORMAL}}));
// Ensure that setting a value overrides the ranged values.
render_text->SetColor(SK_ColorBLUE);
@@ -674,30 +669,18 @@ TEST_P(RenderTextTest, ApplyStyles) {
render_text->ApplyColor(SK_ColorRED, Range(0, text_length));
render_text->ApplyBaselineStyle(SUPERIOR, Range(0, text_length));
render_text->ApplyWeight(Font::Weight::BOLD, Range(2, text_length));
- std::vector<std::pair<size_t, SkColor> > expected_color_end;
- expected_color_end.push_back(std::pair<size_t, SkColor>(0, SK_ColorRED));
- EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color_end));
- std::vector<std::pair<size_t, BaselineStyle>> expected_baseline_end;
- expected_baseline_end.push_back(
- std::pair<size_t, BaselineStyle>(0, SUPERIOR));
- EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline_end));
- std::vector<std::pair<size_t, Font::Weight>> expected_weight_end;
- expected_weight_end.push_back(
- std::pair<size_t, Font::Weight>(0, Font::Weight::NORMAL));
- expected_weight_end.push_back(
- std::pair<size_t, Font::Weight>(2, Font::Weight::BOLD));
- EXPECT_TRUE(test_api()->weights().EqualsForTesting(expected_weight_end));
+
+ EXPECT_TRUE(test_api()->colors().EqualsForTesting({{0, SK_ColorRED}}));
+ EXPECT_TRUE(test_api()->baselines().EqualsForTesting({{0, SUPERIOR}}));
+ EXPECT_TRUE(test_api()->weights().EqualsForTesting(
+ {{0, Font::Weight::NORMAL}, {2, Font::Weight::BOLD}}));
// Ensure ranged values adjust to accommodate text length changes.
render_text->ApplyStyle(ITALIC, true, Range(0, 2));
render_text->ApplyStyle(ITALIC, true, Range(3, 6));
render_text->ApplyStyle(ITALIC, true, Range(7, text_length));
- std::vector<std::pair<size_t, bool> > expected_italic;
- expected_italic.push_back(std::pair<size_t, bool>(0, true));
- expected_italic.push_back(std::pair<size_t, bool>(2, false));
- expected_italic.push_back(std::pair<size_t, bool>(3, true));
- expected_italic.push_back(std::pair<size_t, bool>(6, false));
- expected_italic.push_back(std::pair<size_t, bool>(7, true));
+ std::vector<std::pair<size_t, bool>> expected_italic = {
+ {0, true}, {2, false}, {3, true}, {6, false}, {7, true}};
EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
// Changing the text should clear any breaks except for the first one.
@@ -721,44 +704,42 @@ TEST_P(RenderTextTest, ApplyStyles) {
// Styles shouldn't be changed mid-grapheme.
render_text->SetText(UTF8ToUTF16("0\u0915\u093f1\u0915\u093f2"));
render_text->ApplyStyle(UNDERLINE, true, Range(2, 5));
- std::vector<std::pair<size_t, bool>> expected_underline;
- expected_underline.push_back(std::pair<size_t, bool>(0, false));
- expected_underline.push_back(std::pair<size_t, bool>(1, true));
- expected_underline.push_back(std::pair<size_t, bool>(6, false));
- EXPECT_TRUE(
- test_api()->styles()[UNDERLINE].EqualsForTesting(expected_underline));
+ EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(
+ {{0, false}, {1, true}, {6, false}}));
}
}
TEST_P(RenderTextTest, AppendTextKeepsStyles) {
RenderText* render_text = GetRenderText();
// Setup basic functionality.
- render_text->SetText(UTF8ToUTF16("abc"));
+ render_text->SetText(UTF8ToUTF16("abcd"));
render_text->ApplyColor(SK_ColorRED, Range(0, 1));
render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
render_text->ApplyStyle(UNDERLINE, true, Range(2, 3));
+ render_text->ApplyFontSizeOverride(20, Range(3, 4));
// Verify basic functionality.
- std::vector<std::pair<size_t, SkColor>> expected_color;
- expected_color.push_back(std::pair<size_t, SkColor>(0, SK_ColorRED));
- expected_color.push_back(std::pair<size_t, SkColor>(1, SK_ColorBLACK));
+ const std::vector<std::pair<size_t, SkColor>> expected_color = {
+ {0, SK_ColorRED}, {1, SK_ColorBLACK}};
EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color));
- std::vector<std::pair<size_t, BaselineStyle>> expected_baseline;
- expected_baseline.push_back(
- std::pair<size_t, BaselineStyle>(0, NORMAL_BASELINE));
- expected_baseline.push_back(std::pair<size_t, BaselineStyle>(1, SUPERSCRIPT));
- expected_baseline.push_back(
- std::pair<size_t, BaselineStyle>(2, NORMAL_BASELINE));
+ const std::vector<std::pair<size_t, BaselineStyle>> expected_baseline = {
+ {0, NORMAL_BASELINE}, {1, SUPERSCRIPT}, {2, NORMAL_BASELINE}};
EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline));
- std::vector<std::pair<size_t, bool>> expected_style;
- expected_style.push_back(std::pair<size_t, bool>(0, false));
- expected_style.push_back(std::pair<size_t, bool>(2, true));
+ const std::vector<std::pair<size_t, bool>> expected_style = {
+ {0, false}, {2, true}, {3, false}};
EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
+ const std::vector<std::pair<size_t, int>> expected_font_size = {{0, 0},
+ {3, 20}};
+ EXPECT_TRUE(
+ test_api()->font_size_overrides().EqualsForTesting(expected_font_size));
+
// Ensure AppendText maintains current text styles.
- render_text->AppendText(UTF8ToUTF16("def"));
- EXPECT_EQ(render_text->GetDisplayText(), UTF8ToUTF16("abcdef"));
+ render_text->AppendText(UTF8ToUTF16("efg"));
+ EXPECT_EQ(render_text->GetDisplayText(), UTF8ToUTF16("abcdefg"));
EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color));
EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline));
EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
+ EXPECT_TRUE(
+ test_api()->font_size_overrides().EqualsForTesting(expected_font_size));
}
void TestVisualCursorMotionInObscuredField(
@@ -962,10 +943,6 @@ TEST_P(RenderTextTest, ObscuredEmoji) {
render_text->Draw(canvas());
}
-// TODO(PORT): Fails for RenderTextMac.
-// Crashes on Mac with RenderTextHarfBuzz. See http://crbug.com/640068.
-#if !defined(OS_MACOSX)
-
TEST_P(RenderTextTest, ElidedText) {
// TODO(skanuj) : Add more test cases for following
// - RenderText styles.
@@ -1067,8 +1044,6 @@ TEST_P(RenderTextTest, ElidedObscuredText) {
EXPECT_EQ(elided_obscured_text, render_text->GetDisplayText());
}
-#endif // !defined(OS_MACOSX)
-
// TODO(PORT): Fails for RenderTextMac.
TEST_P(RenderTextHarfBuzzTest, MultilineElide) {
RenderText* render_text = GetRenderText();
@@ -1814,9 +1789,6 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_ComplexScript) {
EXPECT_EQ(0U, render_text->cursor_position());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-// Crashes on Mac with RenderTextHarfBuzz. See http://crbug.com/640068.
-#if !defined(OS_MACOSX)
TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) {
RenderText* render_text = GetRenderText();
// Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
@@ -1841,7 +1813,6 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) {
}
EXPECT_EQ(6U, render_text->cursor_position());
}
-#endif // !defined(OS_MACOSX)
TEST_P(RenderTextHarfBuzzTest, GraphemePositions) {
// LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR abc, and LTR कि.
@@ -2502,26 +2473,26 @@ TEST_P(RenderTextTest, StringSizeEmptyString) {
}
TEST_P(RenderTextTest, StringSizeRespectsFontListMetrics) {
- // Check that Verdana and the CJK font have different font metrics.
- Font verdana_font("Verdana", 16);
- ASSERT_EQ("verdana",
- base::ToLowerASCII(verdana_font.GetActualFontNameForTesting()));
+ // Check that the test font and the CJK font have different font metrics.
+ Font test_font(kTestFontName, 16);
+ ASSERT_EQ(base::ToLowerASCII(kTestFontName),
+ base::ToLowerASCII(test_font.GetActualFontNameForTesting()));
Font cjk_font(kCJKFontName, 16);
ASSERT_EQ(base::ToLowerASCII(kCJKFontName),
base::ToLowerASCII(cjk_font.GetActualFontNameForTesting()));
- EXPECT_NE(verdana_font.GetHeight(), cjk_font.GetHeight());
- EXPECT_NE(verdana_font.GetBaseline(), cjk_font.GetBaseline());
- // "a" should be rendered with Verdana, not with the CJK font.
- const char* verdana_font_text = "a";
+ EXPECT_NE(test_font.GetHeight(), cjk_font.GetHeight());
+ EXPECT_NE(test_font.GetBaseline(), cjk_font.GetBaseline());
+ // "a" should be rendered with the test font, not with the CJK font.
+ const char* test_font_text = "a";
// "円" (U+5168 Han character YEN) should render with the CJK font, not
- // Verdana.
+ // the test font.
const char* cjk_font_text = "\u5168";
- Font smaller_font = verdana_font;
+ Font smaller_font = test_font;
Font larger_font = cjk_font;
- const char* smaller_font_text = verdana_font_text;
+ const char* smaller_font_text = test_font_text;
const char* larger_font_text = cjk_font_text;
- if (cjk_font.GetHeight() < verdana_font.GetHeight() &&
- cjk_font.GetBaseline() < verdana_font.GetBaseline()) {
+ if (cjk_font.GetHeight() < test_font.GetHeight() &&
+ cjk_font.GetBaseline() < test_font.GetBaseline()) {
std::swap(smaller_font, larger_font);
std::swap(smaller_font_text, larger_font_text);
}
@@ -4251,11 +4222,17 @@ TEST_P(RenderTextTest, StringFitsOwnWidth) {
// Ensure that RenderText examines all of the fonts in its FontList before
// falling back to other fonts.
TEST_P(RenderTextHarfBuzzTest, HarfBuzz_FontListFallback) {
+#if defined(OS_LINUX)
+ const char kTestFont[] = "Arimo";
+#else
+ const char kTestFont[] = "Arial";
+#endif
// Double-check that the requested fonts are present.
- FontList font_list(base::StringPrintf("Arial, %s, 12px", kSymbolFontName));
+ std::string format = std::string(kTestFont) + ", %s, 12px";
+ FontList font_list(base::StringPrintf(format.c_str(), kSymbolFontName));
const std::vector<Font>& fonts = font_list.GetFonts();
ASSERT_EQ(2u, fonts.size());
- ASSERT_EQ("arial",
+ ASSERT_EQ(base::ToLowerASCII(kTestFont),
base::ToLowerASCII(fonts[0].GetActualFontNameForTesting()));
ASSERT_EQ(base::ToLowerASCII(kSymbolFontName),
base::ToLowerASCII(fonts[1].GetActualFontNameForTesting()));
@@ -4369,13 +4346,13 @@ TEST_P(RenderTextTest, TextDoesntClip) {
}
{
SCOPED_TRACE("TextDoesntClip Left Side");
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) || \
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
defined(ARCH_CPU_MIPS_FAMILY)
- // TODO(dschuyler): On Windows, Chrome OS, and Mac smoothing draws to the
- // left of text. This appears to be a preexisting issue that wasn't
- // revealed by the prior unit tests. RenderText currently only uses
- // origins and advances and ignores bounding boxes so cannot account for
- // under- and over-hang.
+ // TODO(dschuyler): On Windows, Chrome OS, Linux, and Mac smoothing draws
+ // to the left of text. This appears to be a preexisting issue that
+ // wasn't revealed by the prior unit tests. RenderText currently only
+ // uses origins and advances and ignores bounding boxes so cannot account
+ // for under- and over-hang.
rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize - 1,
string_size.height());
#else
@@ -4385,13 +4362,13 @@ TEST_P(RenderTextTest, TextDoesntClip) {
}
{
SCOPED_TRACE("TextDoesntClip Right Side");
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) || \
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
defined(ARCH_CPU_MIPS_FAMILY)
- // TODO(dschuyler): On Windows, Chrome OS, and Mac smoothing draws to the
- // right of text. This appears to be a preexisting issue that wasn't
- // revealed by the prior unit tests. RenderText currently only uses
- // origins and advances and ignores bounding boxes so cannot account for
- // under- and over-hang.
+ // TODO(dschuyler): On Windows, Chrome OS, Linux, and Mac smoothing draws
+ // to the right of text. This appears to be a preexisting issue that
+ // wasn't revealed by the prior unit tests. RenderText currently only
+ // uses origins and advances and ignores bounding boxes so cannot account
+ // for under- and over-hang.
rect_buffer.EnsureSolidRect(SK_ColorWHITE,
kTestSize + string_size.width() + 1,
kTestSize, kTestSize - 1,
@@ -4574,9 +4551,9 @@ TEST_P(RenderTextTest, SubpixelRenderingSuppressed) {
EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
}
-// Verify GetDecoratedWordAtPoint returns the correct baseline point and
+// Verify GetWordLookupDataAtPoint returns the correct baseline point and
// decorated word for an LTR string.
-TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
+TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_LTR) {
const base::string16 ltr = UTF8ToUTF16(" ab c ");
const int kWordOneStartIndex = 2;
const int kWordTwoStartIndex = 6;
@@ -4621,14 +4598,14 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
{
SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds"));
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(-5, cursor_y), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
}
{
SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds"));
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(105, cursor_y), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
@@ -4641,8 +4618,8 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false)
.origin();
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
- &baseline_point));
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(query, &decorated_word,
+ &baseline_point));
if (i < kWordTwoStartIndex) {
VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
@@ -4654,9 +4631,9 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
}
}
-// Verify GetDecoratedWordAtPoint returns the correct baseline point and
+// Verify GetWordLookupDataAtPoint returns the correct baseline point and
// decorated word for an RTL string.
-TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
+TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_RTL) {
const base::string16 rtl = UTF8ToUTF16(" \u0634\u0632 \u0634");
const int kWordOneStartIndex = 1;
const int kWordTwoStartIndex = 5;
@@ -4699,14 +4676,14 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
{
SCOPED_TRACE(base::StringPrintf("Query to the left of text bounds"));
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(-5, cursor_y), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
}
{
SCOPED_TRACE(base::StringPrintf("Query to the right of text bounds"));
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(105, cursor_y), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
@@ -4721,8 +4698,8 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
render_text->GetCursorBounds(SelectionModel(i, CURSOR_FORWARD), false)
.top_right();
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
- &baseline_point));
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(query, &decorated_word,
+ &baseline_point));
if (i < kWordTwoStartIndex) {
VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
@@ -4733,8 +4710,8 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
}
}
-// Test that GetDecoratedWordAtPoint behaves correctly for multiline text.
-TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Multiline) {
+// Test that GetWordLookupDataAtPoint behaves correctly for multiline text.
+TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Multiline) {
const base::string16 text = UTF8ToUTF16("a b\n..\ncd.");
const size_t kWordOneIndex = 0; // Index of character 'a'.
const size_t kWordTwoIndex = 2; // Index of character 'b'.
@@ -4784,36 +4761,36 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Multiline) {
Point baseline_point;
{
// Query to the left of the first line.
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(-5, GetCursorYForTesting(0)), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
}
{
// Query on the second line.
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(5, GetCursorYForTesting(1)), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
}
{
// Query at the center point of the character 'c'.
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
left_glyph_word_3.CenterPoint(), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_3, decorated_word);
EXPECT_TRUE(left_glyph_word_3.Contains(baseline_point));
}
{
// Query to the right of the third line.
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(
Point(505, GetCursorYForTesting(2)), &decorated_word, &baseline_point));
VerifyDecoratedWordsAreEqual(expected_word_3, decorated_word);
EXPECT_TRUE(left_glyph_word_3.Contains(baseline_point));
}
}
-// Verify the boolean return value of GetDecoratedWordAtPoint.
-TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) {
+// Verify the boolean return value of GetWordLookupDataAtPoint.
+TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Return) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("..."));
@@ -4824,21 +4801,90 @@ TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) {
Point query =
render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
.origin();
- EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
- &baseline_point));
+ EXPECT_FALSE(render_text->GetWordLookupDataAtPoint(query, &decorated_word,
+ &baseline_point));
render_text->SetText(UTF8ToUTF16("abc"));
query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
.origin();
- EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
- &baseline_point));
+ EXPECT_TRUE(render_text->GetWordLookupDataAtPoint(query, &decorated_word,
+ &baseline_point));
// False should be returned for obscured text.
render_text->SetObscured(true);
query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
.origin();
- EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
- &baseline_point));
+ EXPECT_FALSE(render_text->GetWordLookupDataAtPoint(query, &decorated_word,
+ &baseline_point));
+}
+
+// Test that GetLookupDataAtPoint behaves correctly when the range spans lines.
+TEST_P(RenderTextHarfBuzzTest, GetLookupDataAtRange_Multiline) {
+ const base::string16 text = UTF8ToUTF16("a\nb");
+ constexpr Range kWordOneRange = Range(0, 1); // Range of character 'a'.
+ constexpr Range kWordTwoRange = Range(2, 3); // Range of character 'b'.
+ constexpr Range kTextRange = Range(0, 3); // Range of the entire text.
+
+ // Set up render text. Apply style ranges so that each character index gets
+ // a corresponding font.
+ RenderText* render_text = GetRenderText();
+ render_text->SetMultiline(true);
+ render_text->SetDisplayRect(Rect(500, 500));
+ render_text->SetText(text);
+ render_text->ApplyWeight(Font::Weight::SEMIBOLD, kWordOneRange);
+ render_text->ApplyStyle(UNDERLINE, true, kWordTwoRange);
+
+ // Set up test expectations.
+ const std::vector<RenderText::FontSpan> font_spans =
+ render_text->GetFontSpansForTesting();
+
+ DecoratedText expected_word_1;
+ expected_word_1.text = UTF8ToUTF16("a");
+ expected_word_1.attributes.push_back(CreateRangedAttribute(
+ font_spans, 0, kWordOneRange.start(), Font::Weight::SEMIBOLD, 0));
+ const Rect left_glyph_word_1 = GetSubstringBoundsUnion(kWordOneRange);
+
+ DecoratedText expected_word_2;
+ expected_word_2.text = UTF8ToUTF16("b");
+ expected_word_2.attributes.push_back(
+ CreateRangedAttribute(font_spans, 0, kWordTwoRange.start(),
+ Font::Weight::NORMAL, UNDERLINE_MASK));
+ const Rect left_glyph_word_2 = GetSubstringBoundsUnion(kWordTwoRange);
+
+ DecoratedText expected_entire_text;
+ expected_entire_text.text = UTF8ToUTF16("a\nb");
+ expected_entire_text.attributes.push_back(
+ CreateRangedAttribute(font_spans, kWordOneRange.start(),
+ kWordOneRange.start(), Font::Weight::SEMIBOLD, 0));
+ expected_entire_text.attributes.push_back(
+ CreateRangedAttribute(font_spans, 1, 1, Font::Weight::NORMAL, 0));
+ expected_entire_text.attributes.push_back(CreateRangedAttribute(
+ font_spans, kWordTwoRange.start(), kWordTwoRange.start(),
+ Font::Weight::NORMAL, UNDERLINE_MASK));
+
+ DecoratedText decorated_word;
+ Point baseline_point;
+ {
+ // Query for the range of the first word.
+ EXPECT_TRUE(render_text->GetLookupDataForRange(
+ kWordOneRange, &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_1, decorated_word);
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+ }
+ {
+ // Query for the range of the second word.
+ EXPECT_TRUE(render_text->GetLookupDataForRange(
+ kWordTwoRange, &decorated_word, &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_word_2, decorated_word);
+ EXPECT_TRUE(left_glyph_word_2.Contains(baseline_point));
+ }
+ {
+ // Query the entire text range.
+ EXPECT_TRUE(render_text->GetLookupDataForRange(kTextRange, &decorated_word,
+ &baseline_point));
+ VerifyDecoratedWordsAreEqual(expected_entire_text, decorated_word);
+ EXPECT_TRUE(left_glyph_word_1.Contains(baseline_point));
+ }
}
// Tests text selection made at end points of individual lines of multiline
@@ -5166,6 +5212,24 @@ TEST_P(RenderTextHarfBuzzTest, GlyphSpacing) {
EXPECT_EQ(width_without_glyph_spacing + total_spacing, run->width);
}
+// Ensure font size overrides propagate through to text runs.
+TEST_P(RenderTextHarfBuzzTest, FontSizeOverride) {
+ RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ const int default_font_size = render_text->font_list().GetFontSize();
+ const int test_font_size_override = default_font_size + 5;
+ render_text->SetText(UTF8ToUTF16("0123456789"));
+ render_text->ApplyFontSizeOverride(test_font_size_override, gfx::Range(3, 7));
+ test_api()->EnsureLayout();
+ EXPECT_EQ(ToString16Vec({"012", "3456", "789"}), GetRunListStrings());
+
+ const internal::TextRunList* run_list = GetHarfBuzzRunList();
+ ASSERT_EQ(3U, run_list->size());
+
+ EXPECT_EQ(default_font_size, run_list->runs()[0].get()->font_size);
+ EXPECT_EQ(test_font_size_override, run_list->runs()[1].get()->font_size);
+ EXPECT_EQ(default_font_size, run_list->runs()[2].get()->font_size);
+}
+
// Prefix for test instantiations intentionally left blank since each test
// fixture class has a single parameterization.
#if defined(OS_MACOSX)
diff --git a/chromium/ui/gfx/skia_paint_util.cc b/chromium/ui/gfx/skia_paint_util.cc
index df9dcded399..50279d1dbc7 100644
--- a/chromium/ui/gfx/skia_paint_util.cc
+++ b/chromium/ui/gfx/skia_paint_util.cc
@@ -4,10 +4,9 @@
#include "ui/gfx/skia_paint_util.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/paint_image_builder.h"
#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
#include "ui/gfx/image/image_skia_rep.h"
@@ -87,11 +86,10 @@ sk_sp<SkDrawLooper> CreateShadowDrawLooper(
SkIntToScalar(shadow.y()));
SkPaint* paint = looper_builder.addLayer(layer_info);
- // SkBlurMaskFilter's blur radius defines the range to extend the blur from
+ // Skia's blur radius defines the range to extend the blur from
// original mask, which is half of blur amount as defined in ShadowValue.
- paint->setMaskFilter(SkBlurMaskFilter::Make(
- kNormal_SkBlurStyle, RadiusToSigma(shadow.blur() / 2),
- SkBlurMaskFilter::kHighQuality_BlurFlag));
+ paint->setMaskFilter(SkMaskFilter::MakeBlur(
+ kNormal_SkBlurStyle, RadiusToSigma(shadow.blur() / 2)));
paint->setColorFilter(
SkColorFilter::MakeModeFilter(shadow.color(), SkBlendMode::kSrcIn));
}
diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc
index 2fbae69129c..4379e76c584 100644
--- a/chromium/ui/gfx/skia_util.cc
+++ b/chromium/ui/gfx/skia_util.cc
@@ -12,7 +12,6 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
-#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -69,6 +68,10 @@ SkSize SizeFToSkSize(const SizeF& size) {
SkFloatToScalar(size.height()));
}
+SkISize SizeToSkISize(const Size& size) {
+ return SkISize::Make(size.width(), size.height());
+}
+
SizeF SkSizeToSizeF(const SkSize& size) {
return SizeF(SkScalarToFloat(size.width()), SkScalarToFloat(size.height()));
}
diff --git a/chromium/ui/gfx/skia_util.h b/chromium/ui/gfx/skia_util.h
index 0c1f251f7fc..d0efa6b14d2 100644
--- a/chromium/ui/gfx/skia_util.h
+++ b/chromium/ui/gfx/skia_util.h
@@ -35,6 +35,7 @@ GFX_EXPORT Rect SkIRectToRect(const SkIRect& rect);
GFX_EXPORT SkRect RectFToSkRect(const RectF& rect);
GFX_EXPORT RectF SkRectToRectF(const SkRect& rect);
GFX_EXPORT SkSize SizeFToSkSize(const SizeF& size);
+GFX_EXPORT SkISize SizeToSkISize(const Size& size);
GFX_EXPORT SizeF SkSizeToSizeF(const SkSize& size);
GFX_EXPORT Size SkISizeToSize(const SkISize& size);
diff --git a/chromium/ui/gfx/vector_icon_types.h b/chromium/ui/gfx/vector_icon_types.h
index fae6871dffb..e03aa12657a 100644
--- a/chromium/ui/gfx/vector_icon_types.h
+++ b/chromium/ui/gfx/vector_icon_types.h
@@ -63,9 +63,6 @@ enum CommandType {
// Parameters are delay (ms), duration (ms), and tween type
// (gfx::Tween::Type).
TRANSITION_END,
- // Marks the end of the list of commands. TODO(estade): remove this sentinel
- // value and rely on VectorIcon::path_size.
- END
};
// A POD that describes either a path command or an argument for it.
@@ -79,18 +76,29 @@ struct PathElement {
};
};
-struct VectorIcon {
- VectorIcon() = default;
+// Describes the drawing commands for a single vector icon at a particular pixel
+// size or range of sizes.
+struct VectorIconRep {
+ VectorIconRep() = default;
- bool is_empty() const { return !path; }
+ const PathElement* path = nullptr;
- const gfx::PathElement* path = nullptr;
// The length of |path|.
size_t path_size = 0u;
- const gfx::PathElement* path_1x = nullptr;
- // The length of |path_1x|.
- size_t path_1x_size = 0u;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VectorIconRep);
+};
+
+// A vector icon that stores one or more representations to be used for various
+// scale factors and pixel dimensions.
+struct VectorIcon {
+ VectorIcon() = default;
+
+ bool is_empty() const { return !rep; }
+
+ const VectorIconRep* rep = nullptr;
+ const VectorIconRep* rep_1x = nullptr;
// A human-readable name, useful for debugging, derived from the name of the
// icon file. This can also be used as an identifier, but vector icon targets
diff --git a/chromium/ui/gfx/x/x11.h b/chromium/ui/gfx/x/x11.h
index eb53d6dd906..4bce2bc3a34 100644
--- a/chromium/ui/gfx/x/x11.h
+++ b/chromium/ui/gfx/x/x11.h
@@ -89,6 +89,7 @@ extern "C" {
#undef Bool // Defined by X11/Xlib.h to int
#undef RootWindow // Defined by X11/Xlib.h
#undef DestroyAll // Defined by X11/X.h to 0
+#undef AddToList // Defined by X11/extensions/XI.h to 0
#undef COUNT // Defined by X11/extensions/XI.h to 0
#undef CREATE // Defined by X11/extensions/XI.h to 1
#undef DeviceAdded // Defined by X11/extensions/XI.h to 0
diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn
index 238df5099a5..a79f2efbff8 100644
--- a/chromium/ui/gl/BUILD.gn
+++ b/chromium/ui/gl/BUILD.gn
@@ -11,9 +11,10 @@ import("//ui/ozone/ozone.gni")
import("//testing/test.gni")
declare_args() {
- enable_swiftshader = (is_win || (is_linux && use_x11) ||
- (is_chromeos && ozone_platform_x11)) &&
- (target_cpu == "x86" || target_cpu == "x64")
+ enable_swiftshader =
+ (is_win || (is_linux && use_x11) || (is_mac && use_egl) ||
+ (is_chromeos && ozone_platform_x11)) &&
+ (target_cpu == "x86" || target_cpu == "x64")
}
use_glx = use_x11 || ozone_platform_x11
@@ -25,6 +26,7 @@ if (is_android) {
buildflag_header("gl_features") {
header = "gl_features.h"
+ use_egl_on_mac = use_egl && is_mac
flags = [
"ENABLE_SWIFTSHADER=$enable_swiftshader",
"USE_EGL_ON_MAC=$use_egl_on_mac",
@@ -196,7 +198,7 @@ component("gl") {
"gl_surface_egl.h",
]
- if (is_linux) {
+ if (is_linux || (is_win && use_ozone)) {
sources += [
"gl_image_native_pixmap.cc",
"gl_image_native_pixmap.h",
@@ -214,7 +216,7 @@ component("gl") {
}
}
- if (is_posix) {
+ if (is_posix || is_fuchsia) {
# Windows has USE_EGL but doesn't support base::FileDescriptor
sources += [
"gl_fence_android_native_fence_sync.cc",
@@ -222,7 +224,15 @@ component("gl") {
]
}
}
- if (is_android || is_linux || is_fuchsia) {
+ if (is_mac || use_egl) {
+ sources += [
+ "yuv_to_rgb_converter.cc",
+ "yuv_to_rgb_converter.h",
+ ]
+ }
+
+ # TODO(camurcu): Windows/Ozone uses OSMesa for now. Will be updated.
+ if (is_android || is_linux || is_fuchsia || (is_win && use_ozone)) {
sources += [
"gl_implementation_osmesa.cc",
"gl_implementation_osmesa.h",
@@ -311,8 +321,6 @@ component("gl") {
"gl_image_io_surface.mm",
"scoped_cgl.cc",
"scoped_cgl.h",
- "yuv_to_rgb_converter.cc",
- "yuv_to_rgb_converter.h",
]
libs = [
@@ -331,6 +339,7 @@ component("gl") {
data_deps += [
"//third_party/angle:libEGL",
"//third_party/angle:libGLESv2",
+ "//third_party/swiftshader",
]
}
}
@@ -429,7 +438,7 @@ source_set("run_all_unittests") {
if (use_ozone) {
deps += [
- "//mojo/edk/system",
+ "//mojo/edk",
"//services/service_manager/public/cpp/test:test_support",
"//ui/ozone",
]
diff --git a/chromium/ui/gl/PRESUBMIT.py b/chromium/ui/gl/PRESUBMIT.py
index dad553dd754..290b06c5d06 100644
--- a/chromium/ui/gl/PRESUBMIT.py
+++ b/chromium/ui/gl/PRESUBMIT.py
@@ -23,9 +23,9 @@ def PostUploadHook(cl, change, output_api):
return output_api.EnsureCQIncludeTrybotsAreAdded(
cl,
[
- 'master.tryserver.chromium.linux:linux_optional_gpu_tests_rel',
- 'master.tryserver.chromium.mac:mac_optional_gpu_tests_rel',
- 'master.tryserver.chromium.win:win_optional_gpu_tests_rel',
- 'master.tryserver.chromium.android:android_optional_gpu_tests_rel',
+ 'luci.chromium.try:linux_optional_gpu_tests_rel',
+ 'luci.chromium.try:mac_optional_gpu_tests_rel',
+ 'luci.chromium.try:win_optional_gpu_tests_rel',
+ 'luci.chromium.try:android_optional_gpu_tests_rel',
],
'Automatically added optional GPU tests to run on CQ.')
diff --git a/chromium/ui/gl/egl_bindings_autogen_mock.cc b/chromium/ui/gl/egl_bindings_autogen_mock.cc
index 514c551c468..961eed4d07a 100644
--- a/chromium/ui/gl/egl_bindings_autogen_mock.cc
+++ b/chromium/ui/gl/egl_bindings_autogen_mock.cc
@@ -120,13 +120,13 @@ MockEGLInterface::Mock_eglCreateStreamKHR(EGLDisplay dpy,
}
EGLBoolean GL_BINDING_CALL
-MockEGLInterface::Mock_eglCreateStreamProducerD3DTextureNV12ANGLE(
+MockEGLInterface::Mock_eglCreateStreamProducerD3DTextureANGLE(
EGLDisplay dpy,
EGLStreamKHR stream,
EGLAttrib* attrib_list) {
- MakeFunctionUnique("eglCreateStreamProducerD3DTextureNV12ANGLE");
- return interface_->CreateStreamProducerD3DTextureNV12ANGLE(dpy, stream,
- attrib_list);
+ MakeFunctionUnique("eglCreateStreamProducerD3DTextureANGLE");
+ return interface_->CreateStreamProducerD3DTextureANGLE(dpy, stream,
+ attrib_list);
}
EGLSyncKHR GL_BINDING_CALL
@@ -185,6 +185,27 @@ MockEGLInterface::Mock_eglDupNativeFenceFDANDROID(EGLDisplay dpy,
}
EGLBoolean GL_BINDING_CALL
+MockEGLInterface::Mock_eglExportDMABUFImageMESA(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fds,
+ EGLint* strides,
+ EGLint* offsets) {
+ MakeFunctionUnique("eglExportDMABUFImageMESA");
+ return interface_->ExportDMABUFImageMESA(dpy, image, fds, strides, offsets);
+}
+
+EGLBoolean GL_BINDING_CALL
+MockEGLInterface::Mock_eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fourcc,
+ int* num_planes,
+ EGLuint64KHR* modifiers) {
+ MakeFunctionUnique("eglExportDMABUFImageQueryMESA");
+ return interface_->ExportDMABUFImageQueryMESA(dpy, image, fourcc, num_planes,
+ modifiers);
+}
+
+EGLBoolean GL_BINDING_CALL
MockEGLInterface::Mock_eglGetCompositorTimingANDROID(EGLDisplay dpy,
EGLSurface surface,
EGLint numTimestamps,
@@ -501,15 +522,14 @@ MockEGLInterface::Mock_eglStreamConsumerReleaseKHR(EGLDisplay dpy,
return interface_->StreamConsumerReleaseKHR(dpy, stream);
}
-EGLBoolean GL_BINDING_CALL
-MockEGLInterface::Mock_eglStreamPostD3DTextureNV12ANGLE(
+EGLBoolean GL_BINDING_CALL MockEGLInterface::Mock_eglStreamPostD3DTextureANGLE(
EGLDisplay dpy,
EGLStreamKHR stream,
void* texture,
const EGLAttrib* attrib_list) {
- MakeFunctionUnique("eglStreamPostD3DTextureNV12ANGLE");
- return interface_->StreamPostD3DTextureNV12ANGLE(dpy, stream, texture,
- attrib_list);
+ MakeFunctionUnique("eglStreamPostD3DTextureANGLE");
+ return interface_->StreamPostD3DTextureANGLE(dpy, stream, texture,
+ attrib_list);
}
EGLBoolean GL_BINDING_CALL
@@ -599,9 +619,9 @@ MockEGLInterface::GetGLProcAddress(const char* name) {
return reinterpret_cast<GLFunctionPointerType>(Mock_eglCreatePixmapSurface);
if (strcmp(name, "eglCreateStreamKHR") == 0)
return reinterpret_cast<GLFunctionPointerType>(Mock_eglCreateStreamKHR);
- if (strcmp(name, "eglCreateStreamProducerD3DTextureNV12ANGLE") == 0)
+ if (strcmp(name, "eglCreateStreamProducerD3DTextureANGLE") == 0)
return reinterpret_cast<GLFunctionPointerType>(
- Mock_eglCreateStreamProducerD3DTextureNV12ANGLE);
+ Mock_eglCreateStreamProducerD3DTextureANGLE);
if (strcmp(name, "eglCreateSyncKHR") == 0)
return reinterpret_cast<GLFunctionPointerType>(Mock_eglCreateSyncKHR);
if (strcmp(name, "eglCreateWindowSurface") == 0)
@@ -619,6 +639,12 @@ MockEGLInterface::GetGLProcAddress(const char* name) {
if (strcmp(name, "eglDupNativeFenceFDANDROID") == 0)
return reinterpret_cast<GLFunctionPointerType>(
Mock_eglDupNativeFenceFDANDROID);
+ if (strcmp(name, "eglExportDMABUFImageMESA") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(
+ Mock_eglExportDMABUFImageMESA);
+ if (strcmp(name, "eglExportDMABUFImageQueryMESA") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(
+ Mock_eglExportDMABUFImageQueryMESA);
if (strcmp(name, "eglGetCompositorTimingANDROID") == 0)
return reinterpret_cast<GLFunctionPointerType>(
Mock_eglGetCompositorTimingANDROID);
@@ -715,9 +741,9 @@ MockEGLInterface::GetGLProcAddress(const char* name) {
if (strcmp(name, "eglStreamConsumerReleaseKHR") == 0)
return reinterpret_cast<GLFunctionPointerType>(
Mock_eglStreamConsumerReleaseKHR);
- if (strcmp(name, "eglStreamPostD3DTextureNV12ANGLE") == 0)
+ if (strcmp(name, "eglStreamPostD3DTextureANGLE") == 0)
return reinterpret_cast<GLFunctionPointerType>(
- Mock_eglStreamPostD3DTextureNV12ANGLE);
+ Mock_eglStreamPostD3DTextureANGLE);
if (strcmp(name, "eglSurfaceAttrib") == 0)
return reinterpret_cast<GLFunctionPointerType>(Mock_eglSurfaceAttrib);
if (strcmp(name, "eglSwapBuffers") == 0)
diff --git a/chromium/ui/gl/egl_bindings_autogen_mock.h b/chromium/ui/gl/egl_bindings_autogen_mock.h
index 409e8b526e0..5f4e99afc67 100644
--- a/chromium/ui/gl/egl_bindings_autogen_mock.h
+++ b/chromium/ui/gl/egl_bindings_autogen_mock.h
@@ -55,9 +55,9 @@ Mock_eglCreatePixmapSurface(EGLDisplay dpy,
static EGLStreamKHR GL_BINDING_CALL
Mock_eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list);
static EGLBoolean GL_BINDING_CALL
-Mock_eglCreateStreamProducerD3DTextureNV12ANGLE(EGLDisplay dpy,
- EGLStreamKHR stream,
- EGLAttrib* attrib_list);
+Mock_eglCreateStreamProducerD3DTextureANGLE(EGLDisplay dpy,
+ EGLStreamKHR stream,
+ EGLAttrib* attrib_list);
static EGLSyncKHR GL_BINDING_CALL
Mock_eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list);
static EGLSurface GL_BINDING_CALL
@@ -78,6 +78,18 @@ static EGLBoolean GL_BINDING_CALL Mock_eglDestroySyncKHR(EGLDisplay dpy,
static EGLint GL_BINDING_CALL Mock_eglDupNativeFenceFDANDROID(EGLDisplay dpy,
EGLSyncKHR sync);
static EGLBoolean GL_BINDING_CALL
+Mock_eglExportDMABUFImageMESA(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fds,
+ EGLint* strides,
+ EGLint* offsets);
+static EGLBoolean GL_BINDING_CALL
+Mock_eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fourcc,
+ int* num_planes,
+ EGLuint64KHR* modifiers);
+static EGLBoolean GL_BINDING_CALL
Mock_eglGetCompositorTimingANDROID(EGLDisplay dpy,
EGLSurface surface,
EGLint numTimestamps,
@@ -212,10 +224,10 @@ Mock_eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream);
static EGLBoolean GL_BINDING_CALL
Mock_eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream);
static EGLBoolean GL_BINDING_CALL
-Mock_eglStreamPostD3DTextureNV12ANGLE(EGLDisplay dpy,
- EGLStreamKHR stream,
- void* texture,
- const EGLAttrib* attrib_list);
+Mock_eglStreamPostD3DTextureANGLE(EGLDisplay dpy,
+ EGLStreamKHR stream,
+ void* texture,
+ const EGLAttrib* attrib_list);
static EGLBoolean GL_BINDING_CALL Mock_eglSurfaceAttrib(EGLDisplay dpy,
EGLSurface surface,
EGLint attribute,
diff --git a/chromium/ui/gl/features.gni b/chromium/ui/gl/features.gni
index 75a55a3a095..a09f70fbe3d 100644
--- a/chromium/ui/gl/features.gni
+++ b/chromium/ui/gl/features.gni
@@ -7,11 +7,7 @@ declare_args() {
# False by default, enabling currently supported only on Android
use_static_angle = false
- # Whether experimental support for ANGLE on Mac should be enabled.
- # False by default since it is experimental
- use_egl_on_mac = false
+ # Should EGL support be compiled. Can be overriden to test during bring up
+ # of EGL support on other platforms
+ use_egl = is_win || is_android || is_linux || is_fuchsia
}
-
-# Should EGL support be compiled
-use_egl =
- is_win || is_android || is_linux || is_fuchsia || (is_mac && use_egl_on_mac)
diff --git a/chromium/ui/gl/generate_bindings.py b/chromium/ui/gl/generate_bindings.py
index f5c2c9900bd..c20f860cca5 100755
--- a/chromium/ui/gl/generate_bindings.py
+++ b/chromium/ui/gl/generate_bindings.py
@@ -662,7 +662,7 @@ GL_FUNCTIONS = [
'arguments':
'GLenum target, GLenum pname, GLsizei bufSize, GLsizei* length, '
'void** params', },
-{ 'return_type': 'void',
+{ 'return_type': 'GLuint',
'versions': [{ 'name': 'glGetDebugMessageLog' },
{ 'name': 'glGetDebugMessageLogKHR',
'extensions': ['GL_KHR_debug'] }],
@@ -1834,7 +1834,10 @@ OSMESA_FUNCTIONS = [
'arguments': 'GLint pname, GLint* value', },
{ 'return_type': 'OSMESAproc',
'names': ['OSMesaGetProcAddress'],
- 'arguments': 'const char* funcName', },
+ 'arguments': 'const char* funcName',
+ 'logging_code': """
+ GL_SERVICE_LOG("GL_RESULT: " << reinterpret_cast<void*>(result));
+""", },
{ 'return_type': 'GLboolean',
'names': ['OSMesaMakeCurrent'],
'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
@@ -2019,7 +2022,10 @@ EGL_FUNCTIONS = [
'const EGLint* attrib_list', },
{ 'return_type': '__eglMustCastToProperFunctionPointerType',
'names': ['eglGetProcAddress'],
- 'arguments': 'const char* procname', },
+ 'arguments': 'const char* procname',
+ 'logging_code': """
+ GL_SERVICE_LOG("GL_RESULT: " << reinterpret_cast<void*>(result));
+""", },
{ 'return_type': 'EGLBoolean',
'versions': [{ 'name': 'eglGetSyncAttribKHR',
'extensions': [
@@ -2895,35 +2901,46 @@ void DriverEGL::InitializeExtensionBindings() {
file.write('\n')
file.write('%s Debug%sApi::%sFn(%s) {\n' %
(return_type, set_name.upper(), func['known_as'], arguments))
+ # Strip pointer types.
argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', argument_names)
+ # Replace certain `Type varname` combinations with TYPE_varname.
log_argument_names = re.sub(
r'const char\* ([a-zA-Z0-9_]+)', r'CONSTCHAR_\1', arguments)
log_argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\* ([a-zA-Z0-9_]+)',
r'CONSTVOID_\2', log_argument_names)
log_argument_names = re.sub(
- r'(?<!E)GLenum ([a-zA-Z0-9_]+)', r'GLenum_\1', log_argument_names)
- log_argument_names = re.sub(
r'(?<!E)GLboolean ([a-zA-Z0-9_]+)', r'GLboolean_\1', log_argument_names)
log_argument_names = re.sub(
+ r'GLDEBUGPROC ([a-zA-Z0-9_]+)',
+ r'GLDEBUGPROC_\1', log_argument_names)
+ log_argument_names = re.sub(
+ r'(?<!E)GLenum ([a-zA-Z0-9_]+)', r'GLenum_\1', log_argument_names)
+ # Strip remaining types.
+ log_argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2',
log_argument_names)
+ # One more round of stripping to remove both type parts in `unsigned long`.
log_argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2',
log_argument_names)
+ # Convert TYPE_varname log arguments to the corresponding log expression.
log_argument_names = re.sub(
r'CONSTVOID_([a-zA-Z0-9_]+)',
r'static_cast<const void*>(\1)', log_argument_names)
log_argument_names = re.sub(
r'CONSTCHAR_([a-zA-Z0-9_]+)', r'\1', log_argument_names)
log_argument_names = re.sub(
- r'GLenum_([a-zA-Z0-9_]+)', r'GLEnums::GetStringEnum(\1)',
+ r'GLboolean_([a-zA-Z0-9_]+)', r'GLEnums::GetStringBool(\1)',
log_argument_names)
log_argument_names = re.sub(
- r'GLboolean_([a-zA-Z0-9_]+)', r'GLEnums::GetStringBool(\1)',
+ r'GLDEBUGPROC_([a-zA-Z0-9_]+)',
+ r'reinterpret_cast<void*>(\1)', log_argument_names)
+ log_argument_names = re.sub(
+ r'GLenum_([a-zA-Z0-9_]+)', r'GLEnums::GetStringEnum(\1)',
log_argument_names)
log_argument_names = log_argument_names.replace(',', ' << ", " <<')
if argument_names == 'void' or argument_names == '':
diff --git a/chromium/ui/gl/gl_bindings_api_autogen_gl.h b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
index 851bb00a5ae..2aeddbf61a8 100644
--- a/chromium/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
@@ -436,14 +436,14 @@ void glGetBufferPointervRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
void** params) override;
-void glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) override;
+GLuint glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) override;
GLenum glGetErrorFn(void) override;
void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) override;
void glGetFloatvFn(GLenum pname, GLfloat* params) override;
diff --git a/chromium/ui/gl/gl_bindings_autogen_egl.cc b/chromium/ui/gl/gl_bindings_autogen_egl.cc
index 4a1c1ed9af3..53f3fa140f7 100644
--- a/chromium/ui/gl/gl_bindings_autogen_egl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_egl.cc
@@ -1766,7 +1766,9 @@ __eglMustCastToProperFunctionPointerType DebugEGLApi::eglGetProcAddressFn(
<< "(" << procname << ")");
__eglMustCastToProperFunctionPointerType result =
egl_api_->eglGetProcAddressFn(procname);
- GL_SERVICE_LOG("GL_RESULT: " << result);
+
+ GL_SERVICE_LOG("GL_RESULT: " << reinterpret_cast<void*>(result));
+
return result;
}
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.cc b/chromium/ui/gl/gl_bindings_autogen_gl.cc
index 5897a33b935..193c37c9fc3 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.cc
@@ -3146,16 +3146,16 @@ void GLApiBase::glGetBufferPointervRobustANGLEFn(GLenum target,
params);
}
-void GLApiBase::glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) {
- driver_->fn.glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
- severities, lengths, messageLog);
+GLuint GLApiBase::glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) {
+ return driver_->fn.glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
+ severities, lengths, messageLog);
}
GLenum GLApiBase::glGetErrorFn(void) {
@@ -5917,17 +5917,17 @@ void TraceGLApi::glGetBufferPointervRobustANGLEFn(GLenum target,
params);
}
-void TraceGLApi::glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) {
+GLuint TraceGLApi::glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetDebugMessageLog")
- gl_api_->glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
- severities, lengths, messageLog);
+ return gl_api_->glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
+ severities, lengths, messageLog);
}
GLenum TraceGLApi::glGetErrorFn(void) {
@@ -8646,7 +8646,7 @@ void DebugGLApi::glCullFaceFn(GLenum mode) {
void DebugGLApi::glDebugMessageCallbackFn(GLDEBUGPROC callback,
const void* userParam) {
GL_SERVICE_LOG("glDebugMessageCallback"
- << "(" << callback << ", "
+ << "(" << reinterpret_cast<void*>(callback) << ", "
<< static_cast<const void*>(userParam) << ")");
gl_api_->glDebugMessageCallbackFn(callback, userParam);
}
@@ -9310,14 +9310,14 @@ void DebugGLApi::glGetBufferPointervRobustANGLEFn(GLenum target,
params);
}
-void DebugGLApi::glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) {
+GLuint DebugGLApi::glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) {
GL_SERVICE_LOG("glGetDebugMessageLog"
<< "(" << count << ", " << bufSize << ", "
<< static_cast<const void*>(sources) << ", "
@@ -9326,8 +9326,10 @@ void DebugGLApi::glGetDebugMessageLogFn(GLuint count,
<< static_cast<const void*>(severities) << ", "
<< static_cast<const void*>(lengths) << ", "
<< static_cast<const void*>(messageLog) << ")");
- gl_api_->glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
- severities, lengths, messageLog);
+ GLuint result = gl_api_->glGetDebugMessageLogFn(
+ count, bufSize, sources, types, ids, severities, lengths, messageLog);
+ GL_SERVICE_LOG("GL_RESULT: " << result);
+ return result;
}
GLenum DebugGLApi::glGetErrorFn(void) {
@@ -12879,15 +12881,16 @@ void NoContextGLApi::glGetBufferPointervRobustANGLEFn(GLenum target,
NoContextHelper("glGetBufferPointervRobustANGLE");
}
-void NoContextGLApi::glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) {
+GLuint NoContextGLApi::glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) {
NoContextHelper("glGetDebugMessageLog");
+ return 0U;
}
GLenum NoContextGLApi::glGetErrorFn(void) {
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.h b/chromium/ui/gl/gl_bindings_autogen_gl.h
index 0d5fe329291..353ab3622d7 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.h
@@ -506,14 +506,14 @@ typedef void(GL_BINDING_CALL* glGetBufferPointervRobustANGLEProc)(
GLsizei bufSize,
GLsizei* length,
void** params);
-typedef void(GL_BINDING_CALL* glGetDebugMessageLogProc)(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog);
+typedef GLuint(GL_BINDING_CALL* glGetDebugMessageLogProc)(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog);
typedef GLenum(GL_BINDING_CALL* glGetErrorProc)(void);
typedef void(GL_BINDING_CALL* glGetFenceivNVProc)(GLuint fence,
GLenum pname,
@@ -2434,14 +2434,14 @@ class GL_EXPORT GLApi {
GLsizei bufSize,
GLsizei* length,
void** params) = 0;
- virtual void glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) = 0;
+ virtual GLuint glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) = 0;
virtual GLenum glGetErrorFn(void) = 0;
virtual void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) = 0;
virtual void glGetFloatvFn(GLenum pname, GLfloat* params) = 0;
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.cc b/chromium/ui/gl/gl_bindings_autogen_mock.cc
index 72f639e92b3..cb8e0edd575 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.cc
@@ -1500,7 +1500,7 @@ MockGLInterface::Mock_glGetBufferPointervRobustANGLE(GLenum target,
params);
}
-void GL_BINDING_CALL
+GLuint GL_BINDING_CALL
MockGLInterface::Mock_glGetDebugMessageLog(GLuint count,
GLsizei bufSize,
GLenum* sources,
@@ -1510,11 +1510,11 @@ MockGLInterface::Mock_glGetDebugMessageLog(GLuint count,
GLsizei* lengths,
char* messageLog) {
MakeFunctionUnique("glGetDebugMessageLog");
- interface_->GetDebugMessageLog(count, bufSize, sources, types, ids,
- severities, lengths, messageLog);
+ return interface_->GetDebugMessageLog(count, bufSize, sources, types, ids,
+ severities, lengths, messageLog);
}
-void GL_BINDING_CALL
+GLuint GL_BINDING_CALL
MockGLInterface::Mock_glGetDebugMessageLogKHR(GLuint count,
GLsizei bufSize,
GLenum* sources,
@@ -1524,8 +1524,8 @@ MockGLInterface::Mock_glGetDebugMessageLogKHR(GLuint count,
GLsizei* lengths,
char* messageLog) {
MakeFunctionUnique("glGetDebugMessageLogKHR");
- interface_->GetDebugMessageLog(count, bufSize, sources, types, ids,
- severities, lengths, messageLog);
+ return interface_->GetDebugMessageLog(count, bufSize, sources, types, ids,
+ severities, lengths, messageLog);
}
GLenum GL_BINDING_CALL MockGLInterface::Mock_glGetError(void) {
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.h b/chromium/ui/gl/gl_bindings_autogen_mock.h
index 77e4bf54dd2..edfa3003e8f 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.h
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.h
@@ -617,22 +617,22 @@ static void GL_BINDING_CALL Mock_glGetBufferPointervRobustANGLE(GLenum target,
GLsizei bufSize,
GLsizei* length,
void** params);
-static void GL_BINDING_CALL Mock_glGetDebugMessageLog(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog);
-static void GL_BINDING_CALL Mock_glGetDebugMessageLogKHR(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog);
+static GLuint GL_BINDING_CALL Mock_glGetDebugMessageLog(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog);
+static GLuint GL_BINDING_CALL Mock_glGetDebugMessageLogKHR(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog);
static GLenum GL_BINDING_CALL Mock_glGetError(void);
static void GL_BINDING_CALL Mock_glGetFenceivNV(GLuint fence,
GLenum pname,
diff --git a/chromium/ui/gl/gl_bindings_autogen_osmesa.cc b/chromium/ui/gl/gl_bindings_autogen_osmesa.cc
index 75bd1e9bc87..a72fbf41b62 100644
--- a/chromium/ui/gl/gl_bindings_autogen_osmesa.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_osmesa.cc
@@ -289,7 +289,9 @@ OSMESAproc DebugOSMESAApi::OSMesaGetProcAddressFn(const char* funcName) {
GL_SERVICE_LOG("OSMesaGetProcAddress"
<< "(" << funcName << ")");
OSMESAproc result = osmesa_api_->OSMesaGetProcAddressFn(funcName);
- GL_SERVICE_LOG("GL_RESULT: " << result);
+
+ GL_SERVICE_LOG("GL_RESULT: " << reinterpret_cast<void*>(result));
+
return result;
}
diff --git a/chromium/ui/gl/gl_context_cgl.cc b/chromium/ui/gl/gl_context_cgl.cc
index 6b85039c6dd..d0a1d8fe2d0 100644
--- a/chromium/ui/gl/gl_context_cgl.cc
+++ b/chromium/ui/gl/gl_context_cgl.cc
@@ -156,7 +156,8 @@ void GLContextCGL::Destroy() {
SetCurrentGL(GetCurrentGL());
}
- ScopedCGLSetCurrentContext(static_cast<CGLContextObj>(context_));
+ ScopedCGLSetCurrentContext scoped_set_current(
+ static_cast<CGLContextObj>(context_));
yuv_to_rgb_converters_.clear();
// Rebind the current context's API if needed.
@@ -228,8 +229,8 @@ YUVToRGBConverter* GLContextCGL::GetYUVToRGBConverter(
std::unique_ptr<YUVToRGBConverter>& yuv_to_rgb_converter =
yuv_to_rgb_converters_[color_space];
if (!yuv_to_rgb_converter)
- yuv_to_rgb_converter.reset(
- new YUVToRGBConverter(*GetVersionInfo(), color_space));
+ yuv_to_rgb_converter =
+ std::make_unique<YUVToRGBConverter>(*GetVersionInfo(), color_space);
return yuv_to_rgb_converter.get();
}
diff --git a/chromium/ui/gl/gl_context_egl.cc b/chromium/ui/gl/gl_context_egl.cc
index 8e7043a0325..ae5ebe72ce0 100644
--- a/chromium/ui/gl/gl_context_egl.cc
+++ b/chromium/ui/gl/gl_context_egl.cc
@@ -21,8 +21,9 @@
#include "third_party/khronos/EGL/eglext.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_surface_egl.h"
-
+#include "ui/gl/yuv_to_rgb_converter.h"
#ifndef EGL_CHROMIUM_create_context_bind_generates_resource
#define EGL_CHROMIUM_create_context_bind_generates_resource 1
@@ -62,8 +63,8 @@ namespace gl {
GLContextEGL::GLContextEGL(GLShareGroup* share_group)
: GLContextReal(share_group),
- context_(nullptr),
- display_(nullptr),
+ context_(EGL_NO_CONTEXT),
+ display_(EGL_NO_DISPLAY),
config_(nullptr),
unbind_fbo_on_makecurrent_(false) {}
@@ -204,6 +205,7 @@ bool GLContextEGL::Initialize(GLSurface* compatible_surface,
}
void GLContextEGL::Destroy() {
+ ReleaseYUVToRGBConverters();
if (context_) {
if (!eglDestroyContext(display_, context_)) {
LOG(ERROR) << "eglDestroyContext failed with error "
@@ -214,6 +216,66 @@ void GLContextEGL::Destroy() {
}
}
+YUVToRGBConverter* GLContextEGL::GetYUVToRGBConverter(
+ const gfx::ColorSpace& color_space) {
+ // Make sure YUVToRGBConverter objects never get created when surfaceless EGL
+ // contexts aren't supported since support for surfaceless EGL contexts is
+ // required in order to properly release YUVToRGBConverter objects (see
+ // GLContextEGL::ReleaseYUVToRGBConverters())
+ if (!GLSurfaceEGL::IsEGLSurfacelessContextSupported()) {
+ return nullptr;
+ }
+
+ std::unique_ptr<YUVToRGBConverter>& yuv_to_rgb_converter =
+ yuv_to_rgb_converters_[color_space];
+ if (!yuv_to_rgb_converter) {
+ yuv_to_rgb_converter =
+ std::make_unique<YUVToRGBConverter>(*GetVersionInfo(), color_space);
+ }
+ return yuv_to_rgb_converter.get();
+}
+
+void GLContextEGL::ReleaseYUVToRGBConverters() {
+ if (!yuv_to_rgb_converters_.empty()) {
+ // If this context is not current, bind this context's API so that the YUV
+ // converter can safely destruct
+ GLContext* current_context = GetRealCurrent();
+ if (current_context != this) {
+ SetCurrentGL(GetCurrentGL());
+ }
+
+ EGLContext current_egl_context = eglGetCurrentContext();
+ EGLSurface current_draw_surface = EGL_NO_SURFACE;
+ EGLSurface current_read_surface = EGL_NO_SURFACE;
+ if (context_ != current_egl_context) {
+ current_draw_surface = eglGetCurrentSurface(EGL_DRAW);
+ current_read_surface = eglGetCurrentSurface(EGL_READ);
+ // This call relies on the fact that yuv_to_rgb_converters_ are only ever
+ // allocated in GLImageIOSurfaceEGL::CopyTexImage, which is only on
+ // MacOS, where surfaceless EGL contexts are always supported.
+ if (!eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_)) {
+ DVLOG(1) << "eglMakeCurrent failed with error "
+ << GetLastEGLErrorString();
+ }
+ }
+
+ yuv_to_rgb_converters_.clear();
+
+ // Rebind the current context's API if needed.
+ if (current_context && current_context != this) {
+ SetCurrentGL(current_context->GetCurrentGL());
+ }
+
+ if (context_ != current_egl_context) {
+ if (!eglMakeCurrent(display_, current_draw_surface, current_read_surface,
+ current_egl_context)) {
+ DVLOG(1) << "eglMakeCurrent failed with error "
+ << GetLastEGLErrorString();
+ }
+ }
+ }
+}
+
bool GLContextEGL::MakeCurrent(GLSurface* surface) {
DCHECK(context_);
if (IsCurrent(surface))
diff --git a/chromium/ui/gl/gl_context_egl.h b/chromium/ui/gl/gl_context_egl.h
index 75b2f3208c1..36a01fff7b9 100644
--- a/chromium/ui/gl/gl_context_egl.h
+++ b/chromium/ui/gl/gl_context_egl.h
@@ -5,6 +5,7 @@
#ifndef UI_GL_GL_CONTEXT_EGL_H_
#define UI_GL_GL_CONTEXT_EGL_H_
+#include <map>
#include <string>
#include "base/compiler_specific.h"
@@ -35,17 +36,22 @@ class GL_EXPORT GLContextEGL : public GLContextReal {
void OnSetSwapInterval(int interval) override;
bool WasAllocatedUsingRobustnessExtension() override;
void SetUnbindFboOnMakeCurrent() override;
+ YUVToRGBConverter* GetYUVToRGBConverter(
+ const gfx::ColorSpace& color_space) override;
protected:
~GLContextEGL() override;
private:
void Destroy();
+ void ReleaseYUVToRGBConverters();
EGLContext context_;
EGLDisplay display_;
EGLConfig config_;
bool unbind_fbo_on_makecurrent_;
+ std::map<gfx::ColorSpace, std::unique_ptr<YUVToRGBConverter>>
+ yuv_to_rgb_converters_;
DISALLOW_COPY_AND_ASSIGN(GLContextEGL);
};
diff --git a/chromium/ui/gl/gl_context_glx_unittest.cc b/chromium/ui/gl/gl_context_glx_unittest.cc
index 07df17483f1..c393a792c5f 100644
--- a/chromium/ui/gl/gl_context_glx_unittest.cc
+++ b/chromium/ui/gl/gl_context_glx_unittest.cc
@@ -15,7 +15,16 @@
namespace gl {
-TEST(GLContextGLXTest, DoNotDestroyOnFailedMakeCurrent) {
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+ defined(THREAD_SANITIZER)
+// https://crbug.com/830653
+#define MAYBE_DoNotDestroyOnFailedMakeCurrent \
+ DISABLED_DoNotDestroyOnFailedMakeCurrent
+#else
+#define MAYBE_DoNotDestroyOnFailedMakeCurrent DoNotDestroyOnFailedMakeCurrent
+#endif
+
+TEST(GLContextGLXTest, MAYBE_DoNotDestroyOnFailedMakeCurrent) {
auto* xdisplay = gfx::GetXDisplay();
ASSERT_TRUE(xdisplay);
diff --git a/chromium/ui/gl/gl_fence.h b/chromium/ui/gl/gl_fence.h
index a3d05e60f26..81d80ca9139 100644
--- a/chromium/ui/gl/gl_fence.h
+++ b/chromium/ui/gl/gl_fence.h
@@ -5,8 +5,9 @@
#ifndef UI_GL_GL_FENCE_H_
#define UI_GL_GL_FENCE_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gl/gl_export.h"
diff --git a/chromium/ui/gl/gl_fence_android_native_fence_sync.cc b/chromium/ui/gl/gl_fence_android_native_fence_sync.cc
index ae1b0aa33c2..75ea725ca58 100644
--- a/chromium/ui/gl/gl_fence_android_native_fence_sync.cc
+++ b/chromium/ui/gl/gl_fence_android_native_fence_sync.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_fence_android_native_fence_sync.h"
+#include "base/memory/ptr_util.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/gl/gl_fence_egl.cc b/chromium/ui/gl/gl_fence_egl.cc
index 536346f5395..5973b6e9482 100644
--- a/chromium/ui/gl/gl_fence_egl.cc
+++ b/chromium/ui/gl/gl_fence_egl.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_fence_egl.h"
+#include "base/memory/ptr_util.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_bindings.h"
diff --git a/chromium/ui/gl/gl_gl_api_implementation.cc b/chromium/ui/gl/gl_gl_api_implementation.cc
index 250bb1c2909..2313b1f238e 100644
--- a/chromium/ui/gl/gl_gl_api_implementation.cc
+++ b/chromium/ui/gl/gl_gl_api_implementation.cc
@@ -6,7 +6,6 @@
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
diff --git a/chromium/ui/gl/gl_image.h b/chromium/ui/gl/gl_image.h
index 1b92e741ff0..c23670f2ab1 100644
--- a/chromium/ui/gl/gl_image.h
+++ b/chromium/ui/gl/gl_image.h
@@ -71,7 +71,8 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) = 0;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) = 0;
// Set the color space when image is used as an overlay.
virtual void SetColorSpace(const gfx::ColorSpace& color_space) = 0;
diff --git a/chromium/ui/gl/gl_image_ahardwarebuffer.cc b/chromium/ui/gl/gl_image_ahardwarebuffer.cc
index 3121a95c5a0..f9dd6d814f3 100644
--- a/chromium/ui/gl/gl_image_ahardwarebuffer.cc
+++ b/chromium/ui/gl/gl_image_ahardwarebuffer.cc
@@ -41,7 +41,8 @@ bool GLImageAHardwareBuffer::ScheduleOverlayPlane(
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
diff --git a/chromium/ui/gl/gl_image_ahardwarebuffer.h b/chromium/ui/gl/gl_image_ahardwarebuffer.h
index b3ebd04f35a..6674f1a9a65 100644
--- a/chromium/ui/gl/gl_image_ahardwarebuffer.h
+++ b/chromium/ui/gl/gl_image_ahardwarebuffer.h
@@ -6,6 +6,7 @@
#define UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
#include "base/macros.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_image_egl.h"
@@ -28,7 +29,8 @@ class GL_EXPORT GLImageAHardwareBuffer : public GLImageEGL {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override;
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
diff --git a/chromium/ui/gl/gl_image_dxgi.cc b/chromium/ui/gl/gl_image_dxgi.cc
index 9891680bb15..612dde30783 100644
--- a/chromium/ui/gl/gl_image_dxgi.cc
+++ b/chromium/ui/gl/gl_image_dxgi.cc
@@ -6,6 +6,7 @@
#include <d3d11_1.h>
+#include "base/debug/alias.h"
#include "third_party/khronos/EGL/egl.h"
#include "third_party/khronos/EGL/eglext.h"
#include "ui/gl/gl_angle_util_win.h"
@@ -174,7 +175,8 @@ bool GLImageDXGIBase::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
@@ -235,6 +237,12 @@ bool CopyingGLImageDXGI::Initialize() {
HRESULT hr = d3d11_device_->CreateTexture2D(
&desc, nullptr, decoder_copy_texture_.GetAddressOf());
+ // TODO(sunnyps): Remove after fixing https://crbug.com/794735
+ base::debug::Alias(&hr);
+ HRESULT reason_hr = S_OK;
+ base::debug::Alias(&reason_hr);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED)
+ reason_hr = d3d11_device_->GetDeviceRemovedReason();
CHECK(SUCCEEDED(hr));
EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
diff --git a/chromium/ui/gl/gl_image_dxgi.h b/chromium/ui/gl/gl_image_dxgi.h
index 05157bdbaaa..74bdf59a32a 100644
--- a/chromium/ui/gl/gl_image_dxgi.h
+++ b/chromium/ui/gl/gl_image_dxgi.h
@@ -42,7 +42,8 @@ class GL_EXPORT GLImageDXGIBase : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override;
void Flush() override;
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
diff --git a/chromium/ui/gl/gl_image_egl.h b/chromium/ui/gl/gl_image_egl.h
index b32e9489ef7..e014dc7742b 100644
--- a/chromium/ui/gl/gl_image_egl.h
+++ b/chromium/ui/gl/gl_image_egl.h
@@ -5,9 +5,10 @@
#ifndef UI_GL_GL_IMAGE_EGL_H_
#define UI_GL_GL_IMAGE_EGL_H_
+#include <EGL/eglplatform.h>
+
#include "base/macros.h"
#include "base/threading/thread_checker.h"
-#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_image.h"
@@ -35,12 +36,12 @@ class GL_EXPORT GLImageEGL : public GLImage {
// it is required to pass EGL_NO_CONTEXT. This allows to create an EGLImage
// from an external resource. Then this EGLImage can be converted to a GL
// texture.
- bool Initialize(EGLContext context,
- EGLenum target,
- EGLClientBuffer buffer,
+ bool Initialize(void* context /* EGLContext */,
+ unsigned target /* EGLenum */,
+ void* buffer /* EGLClientBuffer */,
const EGLint* attrs);
- EGLImageKHR egl_image_;
+ void* egl_image_ /* EGLImageKHR */;
const gfx::Size size_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/ui/gl/gl_image_glx.cc b/chromium/ui/gl/gl_image_glx.cc
index 4c4ba1a294a..176e86af488 100644
--- a/chromium/ui/gl/gl_image_glx.cc
+++ b/chromium/ui/gl/gl_image_glx.cc
@@ -13,16 +13,6 @@
namespace gl {
namespace {
-bool ValidFormat(unsigned internalformat) {
- switch (internalformat) {
- case GL_RGB:
- case GL_RGBA:
- return true;
- default:
- return false;
- }
-}
-
int TextureFormat(unsigned internalformat) {
switch (internalformat) {
case GL_RGB:
@@ -189,7 +179,8 @@ bool GLImageGLX::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
@@ -199,4 +190,14 @@ void GLImageGLX::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
// TODO(ericrk): Implement GLImage OnMemoryDump. crbug.com/514914
}
+bool GLImageGLX::ValidFormat(unsigned internalformat) {
+ switch (internalformat) {
+ case GL_RGB:
+ case GL_RGBA:
+ return true;
+ default:
+ return false;
+ }
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_glx.h b/chromium/ui/gl/gl_image_glx.h
index abff58fbb5e..9bd917f6a2b 100644
--- a/chromium/ui/gl/gl_image_glx.h
+++ b/chromium/ui/gl/gl_image_glx.h
@@ -34,7 +34,8 @@ class GL_EXPORT GLImageGLX : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override {}
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
@@ -45,6 +46,8 @@ class GL_EXPORT GLImageGLX : public GLImage {
~GLImageGLX() override;
private:
+ static bool ValidFormat(unsigned internalformat);
+
XID glx_pixmap_;
const gfx::Size size_;
unsigned internalformat_;
diff --git a/chromium/ui/gl/gl_image_io_surface.h b/chromium/ui/gl/gl_image_io_surface.h
index fd9741d9f08..1a5959418dc 100644
--- a/chromium/ui/gl/gl_image_io_surface.h
+++ b/chromium/ui/gl/gl_image_io_surface.h
@@ -58,7 +58,8 @@ class GL_EXPORT GLImageIOSurface : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override;
void Flush() override {}
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
@@ -89,6 +90,7 @@ class GL_EXPORT GLImageIOSurface : public GLImage {
~GLImageIOSurface() override;
virtual bool BindTexImageImpl(unsigned internalformat);
+ static bool ValidFormat(gfx::BufferFormat format);
Type GetType() const override;
class RGBConverter;
diff --git a/chromium/ui/gl/gl_image_io_surface.mm b/chromium/ui/gl/gl_image_io_surface.mm
index 12bb7790c11..8ae7b77c202 100644
--- a/chromium/ui/gl/gl_image_io_surface.mm
+++ b/chromium/ui/gl/gl_image_io_surface.mm
@@ -55,36 +55,6 @@ bool ValidInternalFormat(unsigned internalformat) {
}
}
-bool ValidFormat(gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::RGBA_F16:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::UYVY_422:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- return true;
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::ATC:
- case gfx::BufferFormat::ATCIA:
- case gfx::BufferFormat::DXT1:
- case gfx::BufferFormat::DXT5:
- case gfx::BufferFormat::ETC1:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::RGBX_1010102:
- case gfx::BufferFormat::YVU_420:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
GLenum TextureFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::R_8:
@@ -212,7 +182,8 @@ GLenum ConvertRequestedInternalFormat(GLenum internalformat) {
GLImageIOSurface* GLImageIOSurface::Create(const gfx::Size& size,
unsigned internalformat) {
#if BUILDFLAG(USE_EGL_ON_MAC)
- if (GLContext::GetCurrent()->GetVersionInfo()->is_angle) {
+ if (GLContext::GetCurrent()->GetVersionInfo()->is_angle ||
+ GLContext::GetCurrent()->GetVersionInfo()->is_swiftshader) {
return new GLImageIOSurfaceEGL(size, internalformat);
}
#endif // BUILDFLAG(USE_EGL_ON_MAC)
@@ -413,7 +384,8 @@ bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
NOTREACHED();
return false;
}
@@ -493,4 +465,35 @@ GLImageIOSurface* GLImageIOSurface::FromGLImage(GLImage* image) {
return static_cast<GLImageIOSurface*>(image);
}
+// static
+bool GLImageIOSurface::ValidFormat(gfx::BufferFormat format) {
+ switch (format) {
+ case gfx::BufferFormat::R_8:
+ case gfx::BufferFormat::BGRA_8888:
+ case gfx::BufferFormat::BGRX_8888:
+ case gfx::BufferFormat::RGBA_8888:
+ case gfx::BufferFormat::RGBA_F16:
+ case gfx::BufferFormat::BGRX_1010102:
+ case gfx::BufferFormat::UYVY_422:
+ case gfx::BufferFormat::YUV_420_BIPLANAR:
+ return true;
+ case gfx::BufferFormat::R_16:
+ case gfx::BufferFormat::RG_88:
+ case gfx::BufferFormat::ATC:
+ case gfx::BufferFormat::ATCIA:
+ case gfx::BufferFormat::DXT1:
+ case gfx::BufferFormat::DXT5:
+ case gfx::BufferFormat::ETC1:
+ case gfx::BufferFormat::BGR_565:
+ case gfx::BufferFormat::RGBA_4444:
+ case gfx::BufferFormat::RGBX_8888:
+ case gfx::BufferFormat::RGBX_1010102:
+ case gfx::BufferFormat::YVU_420:
+ return false;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_io_surface_egl.h b/chromium/ui/gl/gl_image_io_surface_egl.h
index 17d96825ec4..aeeee89c590 100644
--- a/chromium/ui/gl/gl_image_io_surface_egl.h
+++ b/chromium/ui/gl/gl_image_io_surface_egl.h
@@ -22,6 +22,7 @@ class GL_EXPORT GLImageIOSurfaceEGL : public GLImageIOSurface {
protected:
~GLImageIOSurfaceEGL() override;
bool BindTexImageImpl(unsigned internalformat) override;
+ bool CopyTexImage(unsigned target) override;
private:
EGLDisplay display_;
diff --git a/chromium/ui/gl/gl_image_io_surface_egl.mm b/chromium/ui/gl/gl_image_io_surface_egl.mm
index 787870d540a..e425d5a315a 100644
--- a/chromium/ui/gl/gl_image_io_surface_egl.mm
+++ b/chromium/ui/gl/gl_image_io_surface_egl.mm
@@ -4,7 +4,12 @@
#include "ui/gl/gl_image_io_surface_egl.h"
+#include "base/callback_helpers.h"
+#include "base/mac/bind_objc_block.h"
+#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/scoped_binders.h"
+#include "ui/gl/yuv_to_rgb_converter.h"
// Enums for the EGL_ANGLE_iosurface_client_buffer extension
#define EGL_IOSURFACE_ANGLE 0x3454
@@ -53,6 +58,7 @@ InternalFormatType BufferFormatToInternalFormatType(gfx::BufferFormat format) {
case gfx::BufferFormat::BGR_565:
case gfx::BufferFormat::RGBA_4444:
case gfx::BufferFormat::RGBX_8888:
+ case gfx::BufferFormat::RGBX_1010102:
case gfx::BufferFormat::YVU_420:
NOTREACHED();
return {GL_NONE, GL_NONE};
@@ -127,7 +133,7 @@ bool GLImageIOSurfaceEGL::BindTexImageImpl(unsigned internalformat) {
EGL_TEXTURE_TYPE_ANGLE, formatType.type,
EGL_NONE, EGL_NONE,
};
- // clang-format off
+ // clang-format on
pbuffer_ = eglCreatePbufferFromClientBuffer(display_, EGL_IOSURFACE_ANGLE,
io_surface_.get(), dummy_config_, attribs);
@@ -151,4 +157,138 @@ bool GLImageIOSurfaceEGL::BindTexImageImpl(unsigned internalformat) {
return true;
}
+bool GLImageIOSurfaceEGL::CopyTexImage(unsigned target) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (format_ != gfx::BufferFormat::YUV_420_BIPLANAR)
+ return false;
+
+ GLContext* gl_context = GLContext::GetCurrent();
+ DCHECK(gl_context);
+
+ YUVToRGBConverter* yuv_to_rgb_converter =
+ gl_context->GetYUVToRGBConverter(color_space_for_yuv_to_rgb_);
+ DCHECK(yuv_to_rgb_converter);
+
+ // Note that state restoration is done explicitly instead of scoped binders to
+ // avoid https://crbug.com/601729.
+ GLint rgb_texture = 0;
+ GLenum target_getter = 0;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ target_getter = GL_TEXTURE_BINDING_2D;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ target_getter = GL_TEXTURE_BINDING_CUBE_MAP;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ target_getter = GL_TEXTURE_BINDING_EXTERNAL_OES;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ target_getter = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+ break;
+ default:
+ NOTIMPLEMENTED() << " Target not supported.";
+ return false;
+ }
+
+ EGLSurface y_surface = EGL_NO_SURFACE;
+ EGLSurface uv_surface = EGL_NO_SURFACE;
+
+ glGetIntegerv(target_getter, &rgb_texture);
+ base::ScopedClosureRunner destroy_resources_runner(base::BindBlock(^{
+ if (y_surface != EGL_NO_SURFACE) {
+ EGLBoolean result =
+ eglReleaseTexImage(display_, y_surface, EGL_BACK_BUFFER);
+ DCHECK(result == EGL_TRUE);
+ result = eglDestroySurface(display_, y_surface);
+ DCHECK(result == EGL_TRUE);
+ }
+ if (uv_surface != EGL_NO_SURFACE) {
+ EGLBoolean result =
+ eglReleaseTexImage(display_, uv_surface, EGL_BACK_BUFFER);
+ DCHECK(result == EGL_TRUE);
+ result = eglDestroySurface(display_, uv_surface);
+ DCHECK(result == EGL_TRUE);
+ }
+ glBindTexture(target, rgb_texture);
+ }));
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, yuv_to_rgb_converter->y_texture());
+ if (glGetError() != GL_NO_ERROR) {
+ LOG(ERROR) << "Can't bind Y texture";
+ return false;
+ }
+
+ // clang-format off
+ const EGLint yAttribs[] = {
+ EGL_WIDTH, size_.width(),
+ EGL_HEIGHT, size_.height(),
+ EGL_IOSURFACE_PLANE_ANGLE, 0,
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE,
+ EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RED,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+ EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE,
+ EGL_NONE, EGL_NONE,
+ };
+ // clang-format on
+
+ y_surface = eglCreatePbufferFromClientBuffer(display_, EGL_IOSURFACE_ANGLE,
+ io_surface_.get(), dummy_config_,
+ yAttribs);
+ if (y_surface == EGL_NO_SURFACE) {
+ LOG(ERROR) << "eglCreatePbufferFromClientBuffer failed, EGL error is "
+ << eglGetError();
+ return false;
+ }
+
+ EGLBoolean result = eglBindTexImage(display_, y_surface, EGL_BACK_BUFFER);
+ if (result != EGL_TRUE) {
+ LOG(ERROR) << "eglBindTexImage failed, EGL error is " << eglGetError();
+ return false;
+ }
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, yuv_to_rgb_converter->uv_texture());
+ if (glGetError() != GL_NO_ERROR) {
+ LOG(ERROR) << "Can't bind UV texture";
+ return false;
+ }
+
+ // clang-format off
+ const EGLint uvAttribs[] = {
+ EGL_WIDTH, size_.width() / 2,
+ EGL_HEIGHT, size_.height() / 2,
+ EGL_IOSURFACE_PLANE_ANGLE, 1,
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE,
+ EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RG,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+ EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE,
+ EGL_NONE, EGL_NONE,
+ };
+ // clang-format on
+
+ uv_surface = eglCreatePbufferFromClientBuffer(display_, EGL_IOSURFACE_ANGLE,
+ io_surface_.get(),
+ dummy_config_, uvAttribs);
+ if (uv_surface == EGL_NO_SURFACE) {
+ LOG(ERROR) << "eglCreatePbufferFromClientBuffer failed, EGL error is "
+ << eglGetError();
+ return false;
+ }
+
+ result = eglBindTexImage(display_, uv_surface, EGL_BACK_BUFFER);
+ if (result != EGL_TRUE) {
+ LOG(ERROR) << "eglBindTexImage failed, EGL error is " << eglGetError();
+ return false;
+ }
+
+ yuv_to_rgb_converter->CopyYUV420ToRGB(target, size_, rgb_texture);
+ if (glGetError() != GL_NO_ERROR) {
+ LOG(ERROR) << "Failed converting from YUV to RGB";
+ return false;
+ }
+
+ return true;
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_memory.cc b/chromium/ui/gl/gl_image_memory.cc
index 1f5b76838bd..167ed71891f 100644
--- a/chromium/ui/gl/gl_image_memory.cc
+++ b/chromium/ui/gl/gl_image_memory.cc
@@ -39,36 +39,6 @@ bool ValidInternalFormat(unsigned internalformat) {
}
}
-bool ValidFormat(gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::ATC:
- case gfx::BufferFormat::ATCIA:
- case gfx::BufferFormat::DXT1:
- case gfx::BufferFormat::DXT5:
- case gfx::BufferFormat::ETC1:
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::RGBX_1010102:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::RGBA_F16:
- return true;
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- case gfx::BufferFormat::UYVY_422:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
bool IsCompressedFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::ATC:
@@ -532,7 +502,8 @@ bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
@@ -546,4 +517,35 @@ unsigned GLImageMemory::GetInternalFormatForTesting(gfx::BufferFormat format) {
return TextureFormat(format);
}
+// static
+bool GLImageMemory::ValidFormat(gfx::BufferFormat format) {
+ switch (format) {
+ case gfx::BufferFormat::ATC:
+ case gfx::BufferFormat::ATCIA:
+ case gfx::BufferFormat::DXT1:
+ case gfx::BufferFormat::DXT5:
+ case gfx::BufferFormat::ETC1:
+ case gfx::BufferFormat::R_8:
+ case gfx::BufferFormat::R_16:
+ case gfx::BufferFormat::RG_88:
+ case gfx::BufferFormat::BGR_565:
+ case gfx::BufferFormat::RGBA_4444:
+ case gfx::BufferFormat::RGBX_8888:
+ case gfx::BufferFormat::RGBA_8888:
+ case gfx::BufferFormat::BGRX_8888:
+ case gfx::BufferFormat::BGRX_1010102:
+ case gfx::BufferFormat::RGBX_1010102:
+ case gfx::BufferFormat::BGRA_8888:
+ case gfx::BufferFormat::RGBA_F16:
+ return true;
+ case gfx::BufferFormat::YVU_420:
+ case gfx::BufferFormat::YUV_420_BIPLANAR:
+ case gfx::BufferFormat::UYVY_422:
+ return false;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_memory.h b/chromium/ui/gl/gl_image_memory.h
index 75a3aef0995..349bbdf3776 100644
--- a/chromium/ui/gl/gl_image_memory.h
+++ b/chromium/ui/gl/gl_image_memory.h
@@ -40,7 +40,8 @@ class GL_EXPORT GLImageMemory : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override {}
Type GetType() const override;
@@ -55,6 +56,8 @@ class GL_EXPORT GLImageMemory : public GLImage {
~GLImageMemory() override;
private:
+ static bool ValidFormat(gfx::BufferFormat format);
+
const gfx::Size size_;
const unsigned internalformat_;
const unsigned char* memory_;
diff --git a/chromium/ui/gl/gl_image_native_pixmap.cc b/chromium/ui/gl/gl_image_native_pixmap.cc
index a917940b89b..26e066f2bbb 100644
--- a/chromium/ui/gl/gl_image_native_pixmap.cc
+++ b/chromium/ui/gl/gl_image_native_pixmap.cc
@@ -9,6 +9,7 @@
#include "ui/gfx/buffer_format_util.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface_egl.h"
#define FOURCC(a, b, c, d) \
@@ -59,36 +60,6 @@ bool ValidInternalFormat(unsigned internalformat, gfx::BufferFormat format) {
}
}
-bool ValidFormat(gfx::BufferFormat format) {
- switch (format) {
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::RGBX_1010102:
- case gfx::BufferFormat::YVU_420:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- return true;
- case gfx::BufferFormat::ATC:
- case gfx::BufferFormat::ATCIA:
- case gfx::BufferFormat::DXT1:
- case gfx::BufferFormat::DXT5:
- case gfx::BufferFormat::ETC1:
- case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBA_F16:
- case gfx::BufferFormat::UYVY_422:
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
EGLint FourCC(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::R_8:
@@ -190,7 +161,8 @@ bool GLImageNativePixmap::Initialize(gfx::NativePixmap* pixmap,
}
if (!ValidInternalFormat(internalformat_, format)) {
- LOG(ERROR) << "Invalid internalformat: " << internalformat_
+ LOG(ERROR) << "Invalid internalformat: "
+ << GLEnums::GetStringEnum(internalformat_)
<< " for format: " << gfx::BufferFormatToString(format);
return false;
}
@@ -299,7 +271,7 @@ gfx::NativePixmapHandle GLImageNativePixmap::ExportHandle() {
if (num_planes > 0 && static_cast<size_t>(num_planes) !=
gfx::NumberOfPlanesForBufferFormat(format)) {
LOG(ERROR) << "Invalid number of planes: " << num_planes
- << " for format: " << static_cast<int>(format);
+ << " for format: " << gfx::BufferFormatToString(format);
return gfx::NativePixmapHandle();
}
@@ -308,8 +280,9 @@ gfx::NativePixmapHandle GLImageNativePixmap::ExportHandle() {
// This can happen if RGBX is implemented using RGBA. Otherwise there is
// a real mistake from the user and we have to fail.
if (internalformat_ == GL_RGB && format != gfx::BufferFormat::RGBA_8888) {
- LOG(ERROR) << "Invalid internalformat: 0x" << std::hex << internalformat_
- << " for format: " << static_cast<int>(format);
+ LOG(ERROR) << "Invalid internalformat: "
+ << GLEnums::GetStringEnum(internalformat_)
+ << " for format: " << gfx::BufferFormatToString(format);
return gfx::NativePixmapHandle();
}
}
@@ -377,10 +350,11 @@ bool GLImageNativePixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
DCHECK(pixmap_);
return pixmap_->ScheduleOverlayPlane(widget, z_order, transform, bounds_rect,
- crop_rect);
+ crop_rect, enable_blend);
}
void GLImageNativePixmap::Flush() {
@@ -448,4 +422,35 @@ unsigned GLImageNativePixmap::GetInternalFormatForTesting(
return GL_NONE;
}
+// static
+bool GLImageNativePixmap::ValidFormat(gfx::BufferFormat format) {
+ switch (format) {
+ case gfx::BufferFormat::R_8:
+ case gfx::BufferFormat::R_16:
+ case gfx::BufferFormat::RG_88:
+ case gfx::BufferFormat::BGR_565:
+ case gfx::BufferFormat::RGBA_8888:
+ case gfx::BufferFormat::RGBX_8888:
+ case gfx::BufferFormat::BGRA_8888:
+ case gfx::BufferFormat::BGRX_8888:
+ case gfx::BufferFormat::BGRX_1010102:
+ case gfx::BufferFormat::RGBX_1010102:
+ case gfx::BufferFormat::YVU_420:
+ case gfx::BufferFormat::YUV_420_BIPLANAR:
+ return true;
+ case gfx::BufferFormat::ATC:
+ case gfx::BufferFormat::ATCIA:
+ case gfx::BufferFormat::DXT1:
+ case gfx::BufferFormat::DXT5:
+ case gfx::BufferFormat::ETC1:
+ case gfx::BufferFormat::RGBA_4444:
+ case gfx::BufferFormat::RGBA_F16:
+ case gfx::BufferFormat::UYVY_422:
+ return false;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_native_pixmap.h b/chromium/ui/gl/gl_image_native_pixmap.h
index 66c985c8f75..7bf1e66aaf2 100644
--- a/chromium/ui/gl/gl_image_native_pixmap.h
+++ b/chromium/ui/gl/gl_image_native_pixmap.h
@@ -36,7 +36,8 @@ class GL_EXPORT GLImageNativePixmap : public gl::GLImageEGL {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override;
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
@@ -49,6 +50,8 @@ class GL_EXPORT GLImageNativePixmap : public gl::GLImageEGL {
~GLImageNativePixmap() override;
private:
+ static bool ValidFormat(gfx::BufferFormat format);
+
unsigned internalformat_;
scoped_refptr<gfx::NativePixmap> pixmap_;
bool has_image_flush_external_;
diff --git a/chromium/ui/gl/gl_image_native_pixmap_unittest.cc b/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
index 99a852db831..a8639cbfa4b 100644
--- a/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
+++ b/chromium/ui/gl/gl_image_native_pixmap_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_image_native_pixmap.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/test/gl_image_test_template.h"
namespace gl {
diff --git a/chromium/ui/gl/gl_image_shared_memory_unittest.cc b/chromium/ui/gl/gl_image_shared_memory_unittest.cc
index e48ed75c8f0..26eb38be4cb 100644
--- a/chromium/ui/gl/gl_image_shared_memory_unittest.cc
+++ b/chromium/ui/gl/gl_image_shared_memory_unittest.cc
@@ -68,9 +68,13 @@ INSTANTIATE_TYPED_TEST_CASE_P(GLImageSharedMemory,
GLImageOddSizeTest,
GLImageTestTypes);
+// https://crbug.com/830653
+#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+ !defined(THREAD_SANITIZER)
INSTANTIATE_TYPED_TEST_CASE_P(GLImageSharedMemory,
GLImageCopyTest,
GLImageTestTypes);
+#endif
class GLImageSharedMemoryPoolTestDelegate : public GLImageTestDelegateBase {
public:
@@ -109,9 +113,13 @@ class GLImageSharedMemoryPoolTestDelegate : public GLImageTestDelegateBase {
int GetAdmissibleError() const { return 0; }
};
+// https://crbug.com/830653
+#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+ !defined(THREAD_SANITIZER)
INSTANTIATE_TYPED_TEST_CASE_P(GLImageSharedMemoryPool,
GLImageCopyTest,
GLImageSharedMemoryPoolTestDelegate);
+#endif
} // namespace
} // namespace gl
diff --git a/chromium/ui/gl/gl_image_stub.cc b/chromium/ui/gl/gl_image_stub.cc
index 3d99c4e7eec..8317cf6dc60 100644
--- a/chromium/ui/gl/gl_image_stub.cc
+++ b/chromium/ui/gl/gl_image_stub.cc
@@ -34,7 +34,8 @@ bool GLImageStub::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
diff --git a/chromium/ui/gl/gl_image_stub.h b/chromium/ui/gl/gl_image_stub.h
index 1c2cd6eb90c..524113f4dae 100644
--- a/chromium/ui/gl/gl_image_stub.h
+++ b/chromium/ui/gl/gl_image_stub.h
@@ -30,7 +30,8 @@ class GL_EXPORT GLImageStub : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override {}
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
diff --git a/chromium/ui/gl/gl_image_surface_texture.cc b/chromium/ui/gl/gl_image_surface_texture.cc
index 40e30a8948b..de07bd7931c 100644
--- a/chromium/ui/gl/gl_image_surface_texture.cc
+++ b/chromium/ui/gl/gl_image_surface_texture.cc
@@ -86,7 +86,8 @@ bool GLImageSurfaceTexture::ScheduleOverlayPlane(
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return false;
}
diff --git a/chromium/ui/gl/gl_image_surface_texture.h b/chromium/ui/gl/gl_image_surface_texture.h
index bd0ffdf2ede..22e3327b27b 100644
--- a/chromium/ui/gl/gl_image_surface_texture.h
+++ b/chromium/ui/gl/gl_image_surface_texture.h
@@ -37,7 +37,8 @@ class GL_EXPORT GLImageSurfaceTexture : public GLImage {
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
void SetColorSpace(const gfx::ColorSpace& color_space) override {}
void Flush() override {}
void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
diff --git a/chromium/ui/gl/gl_implementation.cc b/chromium/ui/gl/gl_implementation.cc
index f4493d63fd4..c9d3d892efe 100644
--- a/chromium/ui/gl/gl_implementation.cc
+++ b/chromium/ui/gl/gl_implementation.cc
@@ -14,7 +14,6 @@
#include "base/macros.h"
#include "base/memory/protected_memory.h"
#include "base/memory/protected_memory_cfi.h"
-#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
diff --git a/chromium/ui/gl/gl_implementation_osmesa.cc b/chromium/ui/gl/gl_implementation_osmesa.cc
index 14fa64897a2..f5090948d24 100644
--- a/chromium/ui/gl/gl_implementation_osmesa.cc
+++ b/chromium/ui/gl/gl_implementation_osmesa.cc
@@ -33,7 +33,14 @@ bool InitializeStaticGLBindingsOSMesaGL() {
}
#endif // !defined(OS_FUCHSIA)
- base::FilePath library_path = module_path.Append("libosmesa.so");
+#if defined(OS_WIN)
+ base::FilePath library_path =
+ module_path.Append(FILE_PATH_LITERAL("osmesa.dll"));
+#else
+ base::FilePath library_path =
+ module_path.Append(FILE_PATH_LITERAL("libosmesa.so"));
+#endif
+
base::NativeLibrary library = LoadLibraryAndPrintError(library_path);
if (!library)
return false;
diff --git a/chromium/ui/gl/gl_mock_autogen_egl.h b/chromium/ui/gl/gl_mock_autogen_egl.h
index c4780e0ed90..8a6f77e0fce 100644
--- a/chromium/ui/gl/gl_mock_autogen_egl.h
+++ b/chromium/ui/gl/gl_mock_autogen_egl.h
@@ -52,7 +52,7 @@ MOCK_METHOD4(CreatePixmapSurface,
const EGLint* attrib_list));
MOCK_METHOD2(CreateStreamKHR,
EGLStreamKHR(EGLDisplay dpy, const EGLint* attrib_list));
-MOCK_METHOD3(CreateStreamProducerD3DTextureNV12ANGLE,
+MOCK_METHOD3(CreateStreamProducerD3DTextureANGLE,
EGLBoolean(EGLDisplay dpy,
EGLStreamKHR stream,
EGLAttrib* attrib_list));
@@ -71,6 +71,18 @@ MOCK_METHOD2(DestroyStreamKHR, EGLBoolean(EGLDisplay dpy, EGLStreamKHR stream));
MOCK_METHOD2(DestroySurface, EGLBoolean(EGLDisplay dpy, EGLSurface surface));
MOCK_METHOD2(DestroySyncKHR, EGLBoolean(EGLDisplay dpy, EGLSyncKHR sync));
MOCK_METHOD2(DupNativeFenceFDANDROID, EGLint(EGLDisplay dpy, EGLSyncKHR sync));
+MOCK_METHOD5(ExportDMABUFImageMESA,
+ EGLBoolean(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fds,
+ EGLint* strides,
+ EGLint* offsets));
+MOCK_METHOD5(ExportDMABUFImageQueryMESA,
+ EGLBoolean(EGLDisplay dpy,
+ EGLImageKHR image,
+ int* fourcc,
+ int* num_planes,
+ EGLuint64KHR* modifiers));
MOCK_METHOD5(GetCompositorTimingANDROID,
EGLBoolean(EGLDisplay dpy,
EGLSurface surface,
@@ -206,7 +218,7 @@ MOCK_METHOD2(StreamConsumerGLTextureExternalKHR,
EGLBoolean(EGLDisplay dpy, EGLStreamKHR stream));
MOCK_METHOD2(StreamConsumerReleaseKHR,
EGLBoolean(EGLDisplay dpy, EGLStreamKHR stream));
-MOCK_METHOD4(StreamPostD3DTextureNV12ANGLE,
+MOCK_METHOD4(StreamPostD3DTextureANGLE,
EGLBoolean(EGLDisplay dpy,
EGLStreamKHR stream,
void* texture,
diff --git a/chromium/ui/gl/gl_mock_autogen_gl.h b/chromium/ui/gl/gl_mock_autogen_gl.h
index c363dd99095..002a1fef8c0 100644
--- a/chromium/ui/gl/gl_mock_autogen_gl.h
+++ b/chromium/ui/gl/gl_mock_autogen_gl.h
@@ -419,14 +419,14 @@ MOCK_METHOD5(GetBufferPointervRobustANGLE,
GLsizei* length,
void** params));
MOCK_METHOD8(GetDebugMessageLog,
- void(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog));
+ GLuint(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog));
MOCK_METHOD0(GetError, GLenum());
MOCK_METHOD3(GetFenceivNV, void(GLuint fence, GLenum pname, GLint* params));
MOCK_METHOD2(GetFloatv, void(GLenum pname, GLfloat* params));
diff --git a/chromium/ui/gl/gl_stub_autogen_gl.cc b/chromium/ui/gl/gl_stub_autogen_gl.cc
index e30dbfd7eaf..80d35bd17fe 100644
--- a/chromium/ui/gl/gl_stub_autogen_gl.cc
+++ b/chromium/ui/gl/gl_stub_autogen_gl.cc
@@ -42,6 +42,17 @@ GLint GLStubApiBase::glGetAttribLocationFn(GLuint program, const char* name) {
return 0;
}
+GLuint GLStubApiBase::glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) {
+ return 0;
+}
+
GLenum GLStubApiBase::glGetErrorFn() {
return 0;
}
diff --git a/chromium/ui/gl/gl_stub_autogen_gl.h b/chromium/ui/gl/gl_stub_autogen_gl.h
index 394cffd7f84..32160fa8d5c 100644
--- a/chromium/ui/gl/gl_stub_autogen_gl.h
+++ b/chromium/ui/gl/gl_stub_autogen_gl.h
@@ -438,14 +438,14 @@ void glGetBufferPointervRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
void** params) override {}
-void glGetDebugMessageLogFn(GLuint count,
- GLsizei bufSize,
- GLenum* sources,
- GLenum* types,
- GLuint* ids,
- GLenum* severities,
- GLsizei* lengths,
- char* messageLog) override {}
+GLuint glGetDebugMessageLogFn(GLuint count,
+ GLsizei bufSize,
+ GLenum* sources,
+ GLenum* types,
+ GLuint* ids,
+ GLenum* severities,
+ GLsizei* lengths,
+ char* messageLog) override;
GLenum glGetErrorFn() override;
void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) override {}
void glGetFloatvFn(GLenum pname, GLfloat* params) override {}
diff --git a/chromium/ui/gl/gl_surface.cc b/chromium/ui/gl/gl_surface.cc
index 584f033f54a..9ec8b0a53ec 100644
--- a/chromium/ui/gl/gl_surface.cc
+++ b/chromium/ui/gl/gl_surface.cc
@@ -157,7 +157,8 @@ bool GLSurface::ScheduleOverlayPlane(int z_order,
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
NOTIMPLEMENTED();
return false;
}
@@ -404,9 +405,10 @@ bool GLSurfaceAdapter::ScheduleOverlayPlane(int z_order,
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
- return surface_->ScheduleOverlayPlane(
- z_order, transform, image, bounds_rect, crop_rect);
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
+ return surface_->ScheduleOverlayPlane(z_order, transform, image, bounds_rect,
+ crop_rect, enable_blend);
}
bool GLSurfaceAdapter::ScheduleDCLayer(
diff --git a/chromium/ui/gl/gl_surface.h b/chromium/ui/gl/gl_surface.h
index 8fad23d2154..ee5ee65f7b6 100644
--- a/chromium/ui/gl/gl_surface.h
+++ b/chromium/ui/gl/gl_surface.h
@@ -216,11 +216,14 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
// |bounds_rect| specify where it is supposed to be on the screen in pixels.
// |crop_rect| specifies the region within the buffer to be placed inside
// |bounds_rect|.
+ // |enable_blend| specifies if alpha blending, with premultiplied alpha
+ // should be applied at scanout.
virtual bool ScheduleOverlayPlane(int z_order,
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect);
+ const gfx::RectF& crop_rect,
+ bool enable_blend);
// Schedule a CALayer to be shown at swap time.
// All arguments correspond to their CALayer properties.
@@ -347,7 +350,8 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
bool SetEnableDCLayers(bool enable) override;
bool IsSurfaceless() const override;
diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc
index f1413f215a3..9c77b7aff23 100644
--- a/chromium/ui/gl/gl_surface_egl.cc
+++ b/chromium/ui/gl/gl_surface_egl.cc
@@ -15,7 +15,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
@@ -131,7 +130,7 @@ bool GLSurfaceEGL::initialized_ = false;
namespace {
-EGLDisplay g_display = EGL_NO_DISPLAY;
+EGLDisplay g_egl_display = EGL_NO_DISPLAY;
EGLNativeDisplayType g_native_display = EGL_DEFAULT_DISPLAY;
const char* g_egl_extensions = nullptr;
@@ -184,9 +183,10 @@ class EGLSyncControlVSyncProvider : public SyncControlVSyncProvider {
int64_t* media_stream_counter,
int64_t* swap_buffer_counter) override {
uint64_t u_system_time, u_media_stream_counter, u_swap_buffer_counter;
- bool result = eglGetSyncValuesCHROMIUM(
- g_display, surface_, &u_system_time,
- &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
+ bool result =
+ eglGetSyncValuesCHROMIUM(g_egl_display, surface_, &u_system_time,
+ &u_media_stream_counter,
+ &u_swap_buffer_counter) == EGL_TRUE;
if (result) {
*system_time = static_cast<int64_t>(u_system_time);
*media_stream_counter = static_cast<int64_t>(u_media_stream_counter);
@@ -411,7 +411,7 @@ EGLConfig ChooseConfig(GLSurfaceFormat format, bool surfaceless) {
EGLConfig config = nullptr;
EGLConfig* config_data = &config;
// Validate if there are any configs for given attribs.
- if (!ValidateEglConfig(g_display, choose_attributes, &num_configs)) {
+ if (!ValidateEglConfig(g_egl_display, choose_attributes, &num_configs)) {
// Try the next renderable_type
continue;
}
@@ -422,8 +422,8 @@ EGLConfig ChooseConfig(GLSurfaceFormat format, bool surfaceless) {
config_data = matching_configs.get();
}
- if (!eglChooseConfig(g_display, choose_attributes, config_data, config_size,
- &num_configs)) {
+ if (!eglChooseConfig(g_egl_display, choose_attributes, config_data,
+ config_size, &num_configs)) {
LOG(ERROR) << "eglChooseConfig failed with error "
<< GetLastEGLErrorString();
return config;
@@ -437,14 +437,14 @@ EGLConfig ChooseConfig(GLSurfaceFormat format, bool surfaceless) {
for (int i = 0; i < num_configs; i++) {
EGLint red, green, blue, alpha;
// Read the relevant attributes of the EGLConfig.
- if (eglGetConfigAttrib(g_display, matching_configs[i], EGL_RED_SIZE,
+ if (eglGetConfigAttrib(g_egl_display, matching_configs[i], EGL_RED_SIZE,
&red) &&
- eglGetConfigAttrib(g_display, matching_configs[i], EGL_BLUE_SIZE,
- &blue) &&
- eglGetConfigAttrib(g_display, matching_configs[i], EGL_GREEN_SIZE,
- &green) &&
- eglGetConfigAttrib(g_display, matching_configs[i], EGL_ALPHA_SIZE,
- &alpha) &&
+ eglGetConfigAttrib(g_egl_display, matching_configs[i],
+ EGL_BLUE_SIZE, &blue) &&
+ eglGetConfigAttrib(g_egl_display, matching_configs[i],
+ EGL_GREEN_SIZE, &green) &&
+ eglGetConfigAttrib(g_egl_display, matching_configs[i],
+ EGL_ALPHA_SIZE, &alpha) &&
alpha == 0 && red == 5 && green == 6 && blue == 5) {
config = matching_configs[i];
match_found = true;
@@ -454,11 +454,12 @@ EGLConfig ChooseConfig(GLSurfaceFormat format, bool surfaceless) {
if (!match_found) {
// To fall back to default 32 bit format, choose with
// the right attributes again.
- if (!ValidateEglConfig(g_display, config_attribs_8888, &num_configs)) {
+ if (!ValidateEglConfig(g_egl_display, config_attribs_8888,
+ &num_configs)) {
// Try the next renderable_type
continue;
}
- if (!eglChooseConfig(g_display, config_attribs_8888, &config, 1,
+ if (!eglChooseConfig(g_egl_display, config_attribs_8888, &config, 1,
&num_configs)) {
LOG(ERROR) << "eglChooseConfig failed with error "
<< GetLastEGLErrorString();
@@ -549,7 +550,7 @@ GLSurfaceFormat GLSurfaceEGL::GetFormat() {
}
EGLDisplay GLSurfaceEGL::GetDisplay() {
- return g_display;
+ return g_egl_display;
}
EGLConfig GLSurfaceEGL::GetConfig() {
@@ -568,7 +569,7 @@ bool GLSurfaceEGL::InitializeOneOff(EGLNativeDisplayType native_display) {
g_driver_egl.InitializeClientExtensionBindings();
InitializeDisplay(native_display);
- if (g_display == EGL_NO_DISPLAY)
+ if (g_egl_display == EGL_NO_DISPLAY)
return false;
// Must be called after InitializeDisplay().
@@ -580,14 +581,14 @@ bool GLSurfaceEGL::InitializeOneOff(EGLNativeDisplayType native_display) {
// static
bool GLSurfaceEGL::InitializeOneOffForTesting() {
g_driver_egl.InitializeClientExtensionBindings();
- g_display = eglGetCurrentDisplay();
+ g_egl_display = eglGetCurrentDisplay();
g_driver_egl.InitializeExtensionBindings();
return InitializeOneOffCommon();
}
// static
bool GLSurfaceEGL::InitializeOneOffCommon() {
- g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
+ g_egl_extensions = eglQueryString(g_egl_display, EGL_EXTENSIONS);
g_egl_create_context_robustness_supported =
HasEGLExtension("EGL_EXT_create_context_robustness");
@@ -690,20 +691,20 @@ bool GLSurfaceEGL::InitializeExtensionSettingsOneOff() {
if (!initialized_)
return false;
g_driver_egl.UpdateConditionalExtensionBindings();
- g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
+ g_egl_extensions = eglQueryString(g_egl_display, EGL_EXTENSIONS);
return true;
}
// static
void GLSurfaceEGL::ShutdownOneOff() {
- angle::ResetPlatform(g_display);
+ angle::ResetPlatform(g_egl_display);
- if (g_display != EGL_NO_DISPLAY) {
+ if (g_egl_display != EGL_NO_DISPLAY) {
DCHECK(g_driver_egl.fn.eglTerminateFn);
- eglTerminate(g_display);
+ eglTerminate(g_egl_display);
}
- g_display = EGL_NO_DISPLAY;
+ g_egl_display = EGL_NO_DISPLAY;
g_egl_extensions = nullptr;
g_egl_create_context_robustness_supported = false;
@@ -723,7 +724,7 @@ void GLSurfaceEGL::ShutdownOneOff() {
// static
EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
- return g_display;
+ return g_egl_display;
}
// static
@@ -792,8 +793,8 @@ GLSurfaceEGL::~GLSurfaceEGL() {}
// static
EGLDisplay GLSurfaceEGL::InitializeDisplay(
EGLNativeDisplayType native_display) {
- if (g_display != EGL_NO_DISPLAY) {
- return g_display;
+ if (g_egl_display != EGL_NO_DISPLAY) {
+ return g_egl_display;
}
g_native_display = native_display;
@@ -846,12 +847,12 @@ EGLDisplay GLSurfaceEGL::InitializeDisplay(
} else {
UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
DISPLAY_TYPE_MAX);
- g_display = display;
+ g_egl_display = display;
break;
}
}
- return g_display;
+ return g_egl_display;
}
NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(
@@ -1361,13 +1362,14 @@ bool NativeViewGLSurfaceEGL::ScheduleOverlayPlane(
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
#if !defined(OS_ANDROID)
NOTIMPLEMENTED();
return false;
#else
- pending_overlays_.push_back(
- GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect));
+ pending_overlays_.push_back(GLSurfaceOverlay(z_order, transform, image,
+ bounds_rect, crop_rect, true));
return true;
#endif
}
@@ -1523,8 +1525,7 @@ void* PbufferGLSurfaceEGL::GetShareHandle() {
return NULL;
void* handle;
- if (!eglQuerySurfacePointerANGLE(g_display,
- GetHandle(),
+ if (!eglQuerySurfacePointerANGLE(g_egl_display, GetHandle(),
EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
&handle)) {
return NULL;
diff --git a/chromium/ui/gl/gl_surface_egl.h b/chromium/ui/gl/gl_surface_egl.h
index 1e8cb17097c..8f7110e22a7 100644
--- a/chromium/ui/gl/gl_surface_egl.h
+++ b/chromium/ui/gl/gl_surface_egl.h
@@ -135,7 +135,8 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
bool FlipsVertically() const override;
bool BuffersFlipped() const override;
diff --git a/chromium/ui/gl/gl_surface_glx.cc b/chromium/ui/gl/gl_surface_glx.cc
index fb426317082..cfca601a772 100644
--- a/chromium/ui/gl/gl_surface_glx.cc
+++ b/chromium/ui/gl/gl_surface_glx.cc
@@ -35,7 +35,6 @@ namespace gl {
namespace {
-Display* g_display = nullptr;
bool g_glx_context_create = false;
bool g_glx_create_context_robustness_supported = false;
bool g_glx_create_context_profile_supported = false;
@@ -150,7 +149,7 @@ class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider {
bool GetSyncValues(int64_t* system_time,
int64_t* media_stream_counter,
int64_t* swap_buffer_counter) override {
- return glXGetSyncValuesOML(g_display, glx_window_, system_time,
+ return glXGetSyncValuesOML(gfx::GetXDisplay(), glx_window_, system_time,
media_stream_counter, swap_buffer_counter);
}
@@ -158,7 +157,8 @@ class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider {
if (!g_glx_get_msc_rate_oml_supported)
return false;
- if (!glXGetMscRateOML(g_display, glx_window_, numerator, denominator)) {
+ if (!glXGetMscRateOML(gfx::GetXDisplay(), glx_window_, numerator,
+ denominator)) {
// Once glXGetMscRateOML has been found to fail, don't try again,
// since each failing call may spew an error message.
g_glx_get_msc_rate_oml_supported = false;
@@ -218,7 +218,7 @@ class SGIVideoSyncProviderThreadShim {
vsync_lock_() {
// This ensures that creation of |parent_window_| has occured when this shim
// is executing in the same thread as the call to create |parent_window_|.
- XSync(g_display, x11::False);
+ XSync(gfx::GetXDisplay(), x11::False);
}
virtual ~SGIVideoSyncProviderThreadShim() {
@@ -346,8 +346,8 @@ class SGIVideoSyncVSyncProvider
const gfx::VSyncProvider::UpdateVSyncCallback& callback) override {
// Only one outstanding request per surface.
if (!pending_callback_) {
- pending_callback_ =
- std::make_unique<gfx::VSyncProvider::UpdateVSyncCallback>(callback);
+ DCHECK(callback);
+ pending_callback_ = callback;
vsync_thread_->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
@@ -370,8 +370,7 @@ class SGIVideoSyncVSyncProvider
void PendingCallbackRunner(const base::TimeTicks timebase,
const base::TimeDelta interval) {
DCHECK(pending_callback_);
- pending_callback_->Run(timebase, interval);
- pending_callback_.reset();
+ std::move(pending_callback_).Run(timebase, interval);
}
scoped_refptr<SGIVideoSyncThread> vsync_thread_;
@@ -379,7 +378,7 @@ class SGIVideoSyncVSyncProvider
// Thread shim through which the sync provider is accessed on |vsync_thread_|.
std::unique_ptr<SGIVideoSyncProviderThreadShim> shim_;
- std::unique_ptr<gfx::VSyncProvider::UpdateVSyncCallback> pending_callback_;
+ gfx::VSyncProvider::UpdateVSyncCallback pending_callback_;
// Raw pointers to sync primitives owned by the shim_.
// These will only be referenced before we post a task to destroy
@@ -415,14 +414,13 @@ bool GLSurfaceGLX::InitializeOneOff() {
// it's own thread.
gfx::InitializeThreadedX11();
- g_display = gfx::GetXDisplay();
- if (!g_display) {
+ if (!gfx::GetXDisplay()) {
LOG(ERROR) << "XOpenDisplay failed.";
return false;
}
int major, minor;
- if (!glXQueryVersion(g_display, &major, &minor)) {
+ if (!glXQueryVersion(gfx::GetXDisplay(), &major, &minor)) {
LOG(ERROR) << "glxQueryVersion failed";
return false;
}
@@ -436,8 +434,9 @@ bool GLSurfaceGLX::InitializeOneOff() {
gl::GLVisualPickerGLX::GetInstance()->system_visual();
g_visual = visual_info.visual;
g_depth = visual_info.depth;
- g_colormap = XCreateColormap(g_display, DefaultRootWindow(g_display),
- visual_info.visual, AllocNone);
+ g_colormap =
+ XCreateColormap(gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()),
+ visual_info.visual, AllocNone);
// We create a dummy unmapped window for both the main Display and the video
// sync Display so that the Nvidia driver can initialize itself before the
@@ -445,8 +444,8 @@ bool GLSurfaceGLX::InitializeOneOff() {
// Unfortunately some fds e.g. /dev/nvidia0 are cached per thread and because
// we can't start threads before the sandbox is set up, these are accessed
// through the broker process. See GpuProcessPolicy::InitGpuBrokerProcess.
- if (!CreateDummyWindow(g_display)) {
- LOG(ERROR) << "CreateDummyWindow(g_display) failed";
+ if (!CreateDummyWindow(gfx::GetXDisplay())) {
+ LOG(ERROR) << "CreateDummyWindow(gfx::GetXDisplay()) failed";
return false;
}
@@ -494,7 +493,6 @@ bool GLSurfaceGLX::InitializeExtensionSettingsOneOff() {
// static
void GLSurfaceGLX::ShutdownOneOff() {
initialized_ = false;
- g_display = nullptr;
g_glx_context_create = false;
g_glx_create_context_robustness_supported = false;
g_glx_create_context_profile_supported = false;
@@ -514,7 +512,7 @@ void GLSurfaceGLX::ShutdownOneOff() {
// static
const char* GLSurfaceGLX::GetGLXExtensions() {
- return glXQueryExtensionsString(g_display, 0);
+ return glXQueryExtensionsString(gfx::GetXDisplay(), 0);
}
// static
@@ -563,7 +561,7 @@ bool GLSurfaceGLX::IsOMLSyncControlSupported() {
}
void* GLSurfaceGLX::GetDisplay() {
- return g_display;
+ return gfx::GetXDisplay();
}
GLSurfaceGLX::~GLSurfaceGLX() {}
@@ -577,7 +575,7 @@ NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
XWindowAttributes attributes;
- if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) {
+ if (!XGetWindowAttributes(gfx::GetXDisplay(), parent_window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_
<< ".";
return false;
@@ -592,24 +590,25 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
memset(&swa, 0, sizeof(swa));
swa.background_pixmap = 0;
swa.bit_gravity = NorthWestGravity;
- window_ = XCreateWindow(g_display, parent_window_, 0, 0, size_.width(),
- size_.height(), 0, CopyFromParent, InputOutput,
- CopyFromParent, CWBackPixmap | CWBitGravity, &swa);
+ window_ =
+ XCreateWindow(gfx::GetXDisplay(), parent_window_, 0, 0, size_.width(),
+ size_.height(), 0, CopyFromParent, InputOutput,
+ CopyFromParent, CWBackPixmap | CWBitGravity, &swa);
if (!window_) {
LOG(ERROR) << "XCreateWindow failed";
return false;
}
- XMapWindow(g_display, window_);
+ XMapWindow(gfx::GetXDisplay(), window_);
RegisterEvents();
- XFlush(g_display);
+ XFlush(gfx::GetXDisplay());
GetConfig();
if (!config_) {
LOG(ERROR) << "Failed to get GLXConfig";
return false;
}
- glx_window_ = glXCreateWindow(g_display, config_, window_, NULL);
+ glx_window_ = glXCreateWindow(gfx::GetXDisplay(), config_, window_, NULL);
if (!glx_window_) {
LOG(ERROR) << "glXCreateWindow failed";
return false;
@@ -647,14 +646,14 @@ void NativeViewGLSurfaceGLX::Destroy() {
presentation_helper_ = nullptr;
vsync_provider_ = nullptr;
if (glx_window_) {
- glXDestroyWindow(g_display, glx_window_);
+ glXDestroyWindow(gfx::GetXDisplay(), glx_window_);
glx_window_ = 0;
}
if (window_) {
UnregisterEvents();
- XDestroyWindow(g_display, window_);
+ XDestroyWindow(gfx::GetXDisplay(), window_);
window_ = 0;
- XFlush(g_display);
+ XFlush(gfx::GetXDisplay());
}
}
@@ -664,7 +663,7 @@ bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size,
bool has_alpha) {
size_ = size;
glXWaitGL();
- XResizeWindow(g_display, window_, size.width(), size.height());
+ XResizeWindow(gfx::GetXDisplay(), window_, size.width(), size.height());
glXWaitX();
return true;
}
@@ -679,7 +678,7 @@ gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers(
GetSize().width(), "height", GetSize().height());
GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
presentation_helper_.get(), callback);
- glXSwapBuffers(g_display, GetDrawableHandle());
+ glXSwapBuffers(gfx::GetXDisplay(), GetDrawableHandle());
return scoped_swap_buffers.result();
}
@@ -701,7 +700,7 @@ bool NativeViewGLSurfaceGLX::SupportsPostSubBuffer() {
void* NativeViewGLSurfaceGLX::GetConfig() {
if (!config_)
- config_ = GetConfigForWindow(g_display, window_);
+ config_ = GetConfigForWindow(gfx::GetXDisplay(), window_);
return config_;
}
@@ -723,7 +722,8 @@ gfx::SwapResult NativeViewGLSurfaceGLX::PostSubBuffer(
GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
presentation_helper_.get(), callback);
- glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
+ glXCopySubBufferMESA(gfx::GetXDisplay(), GetDrawableHandle(), x, y, width,
+ height);
return scoped_swap_buffers.result();
}
@@ -743,9 +743,9 @@ NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
void NativeViewGLSurfaceGLX::ForwardExposeEvent(XEvent* event) {
XEvent forwarded_event = *event;
forwarded_event.xexpose.window = parent_window_;
- XSendEvent(g_display, parent_window_, x11::False, ExposureMask,
+ XSendEvent(gfx::GetXDisplay(), parent_window_, x11::False, ExposureMask,
&forwarded_event);
- XFlush(g_display);
+ XFlush(gfx::GetXDisplay());
}
bool NativeViewGLSurfaceGLX::CanHandleEvent(XEvent* event) {
@@ -768,14 +768,14 @@ UnmappedNativeViewGLSurfaceGLX::UnmappedNativeViewGLSurfaceGLX(
bool UnmappedNativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
DCHECK(!window_);
- gfx::AcceleratedWidget parent_window = DefaultRootWindow(g_display);
+ gfx::AcceleratedWidget parent_window = DefaultRootWindow(gfx::GetXDisplay());
XSetWindowAttributes attrs;
attrs.border_pixel = 0;
attrs.colormap = g_colormap;
- window_ = XCreateWindow(g_display, parent_window, 0, 0, size_.width(),
- size_.height(), 0, g_depth, InputOutput, g_visual,
- CWBorderPixel | CWColormap, &attrs);
+ window_ = XCreateWindow(
+ gfx::GetXDisplay(), parent_window, 0, 0, size_.width(), size_.height(), 0,
+ g_depth, InputOutput, g_visual, CWBorderPixel | CWColormap, &attrs);
if (!window_) {
LOG(ERROR) << "XCreateWindow failed";
return false;
@@ -785,7 +785,7 @@ bool UnmappedNativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
LOG(ERROR) << "Failed to get GLXConfig";
return false;
}
- glx_window_ = glXCreateWindow(g_display, config_, window_, NULL);
+ glx_window_ = glXCreateWindow(gfx::GetXDisplay(), config_, window_, NULL);
if (!glx_window_) {
LOG(ERROR) << "glXCreateWindow failed";
return false;
@@ -796,11 +796,11 @@ bool UnmappedNativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
void UnmappedNativeViewGLSurfaceGLX::Destroy() {
config_ = nullptr;
if (glx_window_) {
- glXDestroyWindow(g_display, glx_window_);
+ glXDestroyWindow(gfx::GetXDisplay(), glx_window_);
glx_window_ = 0;
}
if (window_) {
- XDestroyWindow(g_display, window_);
+ XDestroyWindow(gfx::GetXDisplay(), window_);
window_ = 0;
}
}
@@ -825,7 +825,7 @@ void* UnmappedNativeViewGLSurfaceGLX::GetHandle() {
void* UnmappedNativeViewGLSurfaceGLX::GetConfig() {
if (!config_)
- config_ = GetConfigForWindow(g_display, window_);
+ config_ = GetConfigForWindow(gfx::GetXDisplay(), window_);
return config_;
}
diff --git a/chromium/ui/gl/gl_surface_overlay.cc b/chromium/ui/gl/gl_surface_overlay.cc
index a8a606b8212..0078c78f5ea 100644
--- a/chromium/ui/gl/gl_surface_overlay.cc
+++ b/chromium/ui/gl/gl_surface_overlay.cc
@@ -16,12 +16,14 @@ GLSurfaceOverlay::GLSurfaceOverlay(int z_order,
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect)
+ const gfx::RectF& crop_rect,
+ bool enable_blend)
: z_order_(z_order),
transform_(transform),
image_(image),
bounds_rect_(bounds_rect),
- crop_rect_(crop_rect) {}
+ crop_rect_(crop_rect),
+ enable_blend_(enable_blend) {}
GLSurfaceOverlay::GLSurfaceOverlay(const GLSurfaceOverlay& other) = default;
@@ -30,7 +32,7 @@ GLSurfaceOverlay::~GLSurfaceOverlay() {}
bool GLSurfaceOverlay::ScheduleOverlayPlane(
gfx::AcceleratedWidget widget) const {
return image_->ScheduleOverlayPlane(widget, z_order_, transform_,
- bounds_rect_, crop_rect_);
+ bounds_rect_, crop_rect_, enable_blend_);
}
void GLSurfaceOverlay::Flush() const {
diff --git a/chromium/ui/gl/gl_surface_overlay.h b/chromium/ui/gl/gl_surface_overlay.h
index ac378197224..7adba324a73 100644
--- a/chromium/ui/gl/gl_surface_overlay.h
+++ b/chromium/ui/gl/gl_surface_overlay.h
@@ -23,7 +23,8 @@ class GL_EXPORT GLSurfaceOverlay {
gfx::OverlayTransform transform,
GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect);
+ const gfx::RectF& crop_rect,
+ bool enable_blend);
GLSurfaceOverlay(const GLSurfaceOverlay& other);
~GLSurfaceOverlay();
@@ -39,6 +40,7 @@ class GL_EXPORT GLSurfaceOverlay {
scoped_refptr<GLImage> image_;
gfx::Rect bounds_rect_;
gfx::RectF crop_rect_;
+ bool enable_blend_;
};
} // namespace gl
diff --git a/chromium/ui/gl/gl_surface_wgl.cc b/chromium/ui/gl/gl_surface_wgl.cc
index d3a91b9b00b..f880c831bdd 100644
--- a/chromium/ui/gl/gl_surface_wgl.cc
+++ b/chromium/ui/gl/gl_surface_wgl.cc
@@ -145,7 +145,7 @@ class DisplayWGL {
HDC device_context_;
int pixel_format_;
};
-DisplayWGL* g_display;
+DisplayWGL* g_wgl_display;
} // namespace
// static
@@ -166,12 +166,12 @@ bool GLSurfaceWGL::InitializeOneOff() {
if (initialized_)
return true;
- DCHECK(g_display == NULL);
+ DCHECK(g_wgl_display == NULL);
std::unique_ptr<DisplayWGL> wgl_display(new DisplayWGL);
if (!wgl_display->Init())
return false;
- g_display = wgl_display.release();
+ g_wgl_display = wgl_display.release();
initialized_ = true;
return true;
}
@@ -185,13 +185,13 @@ bool GLSurfaceWGL::InitializeExtensionSettingsOneOff() {
}
void GLSurfaceWGL::InitializeOneOffForTesting() {
- if (g_display == NULL) {
- g_display = new DisplayWGL;
+ if (g_wgl_display == NULL) {
+ g_wgl_display = new DisplayWGL;
}
}
HDC GLSurfaceWGL::GetDisplayDC() {
- return g_display->device_context();
+ return g_wgl_display->device_context();
}
NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window)
@@ -215,19 +215,11 @@ bool NativeViewGLSurfaceWGL::Initialize(GLSurfaceFormat format) {
// Create a child window. WGL has problems using a window handle owned by
// another process.
- child_window_ =
- CreateWindowEx(WS_EX_NOPARENTNOTIFY,
- reinterpret_cast<wchar_t*>(g_display->window_class()),
- L"",
- WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE,
- 0,
- 0,
- rect.right - rect.left,
- rect.bottom - rect.top,
- window_,
- NULL,
- NULL,
- NULL);
+ child_window_ = CreateWindowEx(
+ WS_EX_NOPARENTNOTIFY,
+ reinterpret_cast<wchar_t*>(g_wgl_display->window_class()), L"",
+ WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, rect.right - rect.left,
+ rect.bottom - rect.top, window_, NULL, NULL, NULL);
if (!child_window_) {
LOG(ERROR) << "CreateWindow failed.\n";
Destroy();
@@ -242,8 +234,7 @@ bool NativeViewGLSurfaceWGL::Initialize(GLSurfaceFormat format) {
return false;
}
- if (!SetPixelFormat(device_context_,
- g_display->pixel_format(),
+ if (!SetPixelFormat(device_context_, g_wgl_display->pixel_format(),
&kPixelFormatDescriptor)) {
LOG(ERROR) << "Unable to set the pixel format for GL context.";
Destroy();
@@ -362,10 +353,9 @@ bool PbufferGLSurfaceWGL::Initialize(GLSurfaceFormat format) {
}
const int kNoAttributes[] = { 0 };
- pbuffer_ = wglCreatePbufferARB(g_display->device_context(),
- g_display->pixel_format(),
- size_.width(), size_.height(),
- kNoAttributes);
+ pbuffer_ = wglCreatePbufferARB(g_wgl_display->device_context(),
+ g_wgl_display->pixel_format(), size_.width(),
+ size_.height(), kNoAttributes);
if (!pbuffer_) {
LOG(ERROR) << "Unable to create pbuffer.";
diff --git a/chromium/ui/gl/init/BUILD.gn b/chromium/ui/gl/init/BUILD.gn
index d55a06bf481..d708e6c468b 100644
--- a/chromium/ui/gl/init/BUILD.gn
+++ b/chromium/ui/gl/init/BUILD.gn
@@ -38,7 +38,7 @@ jumbo_component("init") {
"gl_factory_android.cc",
"gl_initializer_android.cc",
]
- } else if (is_win) {
+ } else if (is_win && !use_ozone) {
sources += [
"gl_factory_win.cc",
"gl_initializer_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 283dd1f028f..a1e787e416b 100644
--- a/chromium/ui/gl/init/create_gr_gl_interface.cc
+++ b/chromium/ui/gl/init/create_gr_gl_interface.cc
@@ -460,13 +460,8 @@ sk_sp<const GrGLInterface> CreateGrGLInterface(
functions->fDebugMessageControl = gl->glDebugMessageControlFn;
functions->fDebugMessageInsert = gl->glDebugMessageInsertFn;
- // TODO(piman): Our GL headers are out-of-date and define GLDEBUGPROC
- // incorrectly wrt const-ness.
- functions->fDebugMessageCallback =
- reinterpret_cast<GrGLDebugMessageCallbackProc>(
- gl->glDebugMessageCallbackFn);
- functions->fGetDebugMessageLog =
- reinterpret_cast<GrGLGetDebugMessageLogProc>(gl->glGetDebugMessageLogFn);
+ functions->fDebugMessageCallback = gl->glDebugMessageCallbackFn;
+ functions->fGetDebugMessageLog = gl->glGetDebugMessageLogFn;
functions->fPushDebugGroup = gl->glPushDebugGroupFn;
functions->fPopDebugGroup = gl->glPopDebugGroupFn;
functions->fObjectLabel = gl->glObjectLabelFn;
diff --git a/chromium/ui/gl/init/gl_factory_mac.cc b/chromium/ui/gl/init/gl_factory_mac.cc
index 52544651c31..da1b21fe3e0 100644
--- a/chromium/ui/gl/init/gl_factory_mac.cc
+++ b/chromium/ui/gl/init/gl_factory_mac.cc
@@ -67,6 +67,7 @@ std::vector<GLImplementation> GetAllowedGLImplementations() {
impls.push_back(kGLImplementationDesktopGLCoreProfile);
#if BUILDFLAG(USE_EGL_ON_MAC)
impls.push_back(kGLImplementationEGLGLES2);
+ impls.push_back(kGLImplementationSwiftShaderGL);
#endif // BUILDFLAG(USE_EGL_ON_MAC)
impls.push_back(kGLImplementationDesktopGL);
impls.push_back(kGLImplementationAppleGL);
@@ -90,6 +91,7 @@ scoped_refptr<GLContext> CreateGLContext(GLShareGroup* share_group,
compatible_surface, attribs);
#if BUILDFLAG(USE_EGL_ON_MAC)
case kGLImplementationEGLGLES2:
+ case kGLImplementationSwiftShaderGL:
return InitializeGLContext(new GLContextEGL(share_group),
compatible_surface, attribs);
#endif // BUILDFLAG(USE_EGL_ON_MAC)
@@ -116,7 +118,8 @@ scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) {
case kGLImplementationDesktopGL:
case kGLImplementationDesktopGLCoreProfile:
case kGLImplementationAppleGL:
- case kGLImplementationEGLGLES2: {
+ case kGLImplementationEGLGLES2:
+ case kGLImplementationSwiftShaderGL: {
NOTIMPLEMENTED() << "No onscreen support on Mac.";
return nullptr;
}
@@ -147,6 +150,7 @@ scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat(
new NoOpGLSurface(size), format);
#if BUILDFLAG(USE_EGL_ON_MAC)
case kGLImplementationEGLGLES2:
+ case kGLImplementationSwiftShaderGL:
if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
size.width() == 0 && size.height() == 0) {
return InitializeGLSurfaceWithFormat(new SurfacelessEGL(size), format);
diff --git a/chromium/ui/gl/init/gl_initializer_mac.cc b/chromium/ui/gl/init/gl_initializer_mac.cc
index 3ca3b88be3f..d58e64ff193 100644
--- a/chromium/ui/gl/init/gl_initializer_mac.cc
+++ b/chromium/ui/gl/init/gl_initializer_mac.cc
@@ -11,6 +11,7 @@
#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/native_library.h"
#include "base/path_service.h"
@@ -137,23 +138,42 @@ bool InitializeStaticCGLInternal(GLImplementation implementation) {
const char kGLESv2ANGLELibraryName[] = "libGLESv2.dylib";
const char kEGLANGLELibraryName[] = "libEGL.dylib";
+const char kGLESv2SwiftShaderLibraryName[] = "libswiftshader_libGLESv2.dylib";
+const char kEGLSwiftShaderLibraryName[] = "libswiftshader_libEGL.dylib";
+
bool InitializeStaticEGLInternal(GLImplementation implementation) {
- if (implementation == kGLImplementationSwiftShaderGL) {
- return false;
+ // 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;
+ if (base::mac::AmIBundled()) {
+ base_dir = base::mac::FrameworkBundlePath().Append("Libraries/");
+ } else {
+ if (!PathService::Get(base::FILE_EXE, &base_dir)) {
+ LOG(ERROR) << "PathService::Get failed.";
+ return false;
+ }
+ base_dir = base_dir.DirName();
}
- base::FilePath module_path;
- if (!PathService::Get(base::DIR_MODULE, &module_path)) {
+ base::FilePath glesv2_path;
+ base::FilePath egl_path;
+ if (implementation == kGLImplementationSwiftShaderGL) {
+#if BUILDFLAG(ENABLE_SWIFTSHADER)
+ glesv2_path = base_dir.Append(kGLESv2SwiftShaderLibraryName);
+ egl_path = base_dir.Append(kEGLSwiftShaderLibraryName);
+#else
return false;
+#endif
+ } else {
+ glesv2_path = base_dir.Append(kGLESv2ANGLELibraryName);
+ egl_path = base_dir.Append(kEGLANGLELibraryName);
}
- base::FilePath glesv2_path = module_path.Append(kGLESv2ANGLELibraryName);
base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path);
if (!gles_library) {
return false;
}
- base::FilePath egl_path = module_path.Append(kEGLANGLELibraryName);
base::NativeLibrary egl_library = LoadLibraryAndPrintError(egl_path);
if (!egl_library) {
base::UnloadNativeLibrary(gles_library);
@@ -172,9 +192,11 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
}
SetGLGetProcAddressProc(get_proc_address);
- AddGLNativeLibrary(egl_library);
+ // FIXME: SwiftShader must load symbols from libGLESv2 before libEGL on MacOS
+ // currently
AddGLNativeLibrary(gles_library);
- SetGLImplementation(kGLImplementationEGLGLES2);
+ AddGLNativeLibrary(egl_library);
+ SetGLImplementation(implementation);
InitializeStaticGLBindingsGL();
InitializeStaticGLBindingsEGL();
@@ -197,6 +219,7 @@ bool InitializeGLOneOffPlatform() {
return true;
#if BUILDFLAG(USE_EGL_ON_MAC)
case kGLImplementationEGLGLES2:
+ case kGLImplementationSwiftShaderGL:
if (!GLSurfaceEGL::InitializeOneOff(0)) {
LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
return false;
@@ -229,6 +252,7 @@ bool InitializeStaticGLBindings(GLImplementation implementation) {
return InitializeStaticCGLInternal(implementation);
#if BUILDFLAG(USE_EGL_ON_MAC)
case kGLImplementationEGLGLES2:
+ case kGLImplementationSwiftShaderGL:
return InitializeStaticEGLInternal(implementation);
#endif // BUILDFLAG(USE_EGL_ON_MAC)
case kGLImplementationMockGL:
diff --git a/chromium/ui/gl/yuv_to_rgb_converter.cc b/chromium/ui/gl/yuv_to_rgb_converter.cc
index 73410cb1c04..bf6f8dd044e 100644
--- a/chromium/ui/gl/yuv_to_rgb_converter.cc
+++ b/chromium/ui/gl/yuv_to_rgb_converter.cc
@@ -14,6 +14,12 @@
namespace gl {
namespace {
+const char kVertexHeaderES3[] =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "#define ATTRIBUTE in\n"
+ "#define VARYING out\n";
+
const char kVertexHeaderCompatiblityProfile[] =
"#version 110\n"
"#define ATTRIBUTE attribute\n"
@@ -24,6 +30,14 @@ const char kVertexHeaderCoreProfile[] =
"#define ATTRIBUTE in\n"
"#define VARYING out\n";
+const char kFragmentHeaderES3[] =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "#define VARYING in\n"
+ "#define TEX texture\n"
+ "#define FRAGCOLOR frag_color\n"
+ "out vec4 FRAGCOLOR;\n";
+
const char kFragmentHeaderCompatiblityProfile[] =
"#version 110\n"
"#extension GL_ARB_texture_rectangle : require\n"
@@ -45,7 +59,7 @@ STRINGIZE(
uniform vec2 a_texScale;
VARYING vec2 v_texCoord;
void main() {
- gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
+ gl_Position = vec4(a_position, 0.0, 1.0);
v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5 * a_texScale;
}
);
@@ -75,22 +89,27 @@ YUVToRGBConverter::YUVToRGBConverter(const GLVersionInfo& gl_version_info,
DCHECK(color_transform->CanGetShaderSource());
std::string do_color_conversion = color_transform->GetShaderSource();
+ bool use_es3 = gl_version_info.is_es3;
bool use_core_profile = gl_version_info.is_desktop_core_profile;
glGenFramebuffersEXT(1, &framebuffer_);
vertex_buffer_ = GLHelper::SetupQuadVertexBuffer();
vertex_shader_ = GLHelper::LoadShader(
GL_VERTEX_SHADER,
- base::StringPrintf("%s\n%s",
- use_core_profile ? kVertexHeaderCoreProfile
- : kVertexHeaderCompatiblityProfile,
- kVertexShader)
+ base::StringPrintf(
+ "%s\n%s",
+ use_es3 ? kVertexHeaderES3
+ : (use_core_profile ? kVertexHeaderCoreProfile
+ : kVertexHeaderCompatiblityProfile),
+ kVertexShader)
.c_str());
fragment_shader_ = GLHelper::LoadShader(
GL_FRAGMENT_SHADER,
- base::StringPrintf("%s\n%s\n%s",
- use_core_profile ? kFragmentHeaderCoreProfile
- : kFragmentHeaderCompatiblityProfile,
- do_color_conversion.c_str(), kFragmentShader)
+ base::StringPrintf(
+ "%s\n%s\n%s",
+ use_es3 ? kFragmentHeaderES3
+ : (use_core_profile ? kFragmentHeaderCoreProfile
+ : kFragmentHeaderCompatiblityProfile),
+ do_color_conversion.c_str(), kFragmentShader)
.c_str());
program_ = GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
diff --git a/chromium/ui/keyboard/BUILD.gn b/chromium/ui/keyboard/BUILD.gn
index ccf79d43925..5e5041ae56c 100644
--- a/chromium/ui/keyboard/BUILD.gn
+++ b/chromium/ui/keyboard/BUILD.gn
@@ -16,6 +16,8 @@ jumbo_component("keyboard") {
"container_floating_behavior.h",
"container_full_width_behavior.cc",
"container_full_width_behavior.h",
+ "display_util.cc",
+ "display_util.h",
"drag_descriptor.cc",
"drag_descriptor.h",
"keyboard_controller.cc",
@@ -27,6 +29,8 @@ jumbo_component("keyboard") {
"keyboard_layout_delegate.h",
"keyboard_layout_manager.cc",
"keyboard_layout_manager.h",
+ "keyboard_resource_util.cc",
+ "keyboard_resource_util.h",
"keyboard_switches.cc",
"keyboard_switches.h",
"keyboard_ui.cc",
@@ -37,11 +41,14 @@ jumbo_component("keyboard") {
"notification_manager.h",
"queued_container_type.cc",
"queued_container_type.h",
+ "queued_display_change.cc",
+ "queued_display_change.h",
]
defines = [ "KEYBOARD_IMPLEMENTATION" ]
deps = [
+ ":resources",
"//base",
"//ui/aura",
"//ui/base",
@@ -58,27 +65,6 @@ jumbo_component("keyboard") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
-}
-
-jumbo_component("keyboard_with_content") {
- sources = [
- "content/keyboard.cc",
- "content/keyboard.h",
- "content/keyboard_constants.cc",
- "content/keyboard_constants.h",
- "content/keyboard_content_util.cc",
- "content/keyboard_content_util.h",
- ]
-
- defines = [ "KEYBOARD_IMPLEMENTATION" ]
-
- deps = [
- ":keyboard",
- ":resources",
- "//base",
- "//ui/base",
- "//url",
- ]
data_deps = [
":resources",
@@ -165,11 +151,10 @@ test("keyboard_unittests") {
deps = [
":keyboard",
- ":keyboard_with_content",
":test_support",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//testing/gtest",
"//ui/aura:test_support",
"//ui/base",
diff --git a/chromium/ui/keyboard/container_behavior.h b/chromium/ui/keyboard/container_behavior.h
index d641d88bff6..346ead117ee 100644
--- a/chromium/ui/keyboard/container_behavior.h
+++ b/chromium/ui/keyboard/container_behavior.h
@@ -39,10 +39,11 @@ class KEYBOARD_EXPORT ContainerBehavior {
// Used by the layout manager to intercept any bounds setting request to
// adjust the request to different bounds, if necessary. This method gets
- // called at any time during the keyboard's life cycle.
+ // called at any time during the keyboard's life cycle. The bounds are in
+ // global screen coordinates.
virtual const gfx::Rect AdjustSetBoundsRequest(
const gfx::Rect& display_bounds,
- const gfx::Rect& requested_bounds) = 0;
+ const gfx::Rect& requested_bounds_in_screen_coords) = 0;
// Used to set the bounds to the default location. This is generally called
// during initialization, but may also be have identical behavior to
@@ -63,8 +64,8 @@ class KEYBOARD_EXPORT ContainerBehavior {
virtual void SavePosition(const gfx::Rect& keyboard_bounds,
const gfx::Size& screen_size) = 0;
- virtual void HandlePointerEvent(const ui::LocatedEvent& event,
- const gfx::Rect& display_bounds) = 0;
+ virtual bool HandlePointerEvent(const ui::LocatedEvent& event,
+ const display::Display& current_display) = 0;
virtual ContainerType GetType() const = 0;
diff --git a/chromium/ui/keyboard/container_floating_behavior.cc b/chromium/ui/keyboard/container_floating_behavior.cc
index 855cdc202cf..7a0c6a03f07 100644
--- a/chromium/ui/keyboard/container_floating_behavior.cc
+++ b/chromium/ui/keyboard/container_floating_behavior.cc
@@ -4,6 +4,7 @@
#include "ui/keyboard/container_floating_behavior.h"
+#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -115,20 +116,20 @@ gfx::Rect ContainerFloatingBehavior::ContainKeyboardToScreenBounds(
int bottom = keyboard_bounds.bottom();
// Prevent keyboard from appearing off screen or overlapping with the edge.
- if (left < 0) {
- left = 0;
- right = keyboard_bounds.width();
+ if (left < display_bounds.x()) {
+ left = display_bounds.x();
+ right = left + keyboard_bounds.width();
}
- if (right >= display_bounds.width()) {
- right = display_bounds.width();
+ if (right >= display_bounds.right()) {
+ right = display_bounds.right();
left = right - keyboard_bounds.width();
}
- if (top < 0) {
- top = 0;
- bottom = keyboard_bounds.height();
+ if (top < display_bounds.y()) {
+ top = display_bounds.y();
+ bottom = top + keyboard_bounds.height();
}
- if (bottom >= display_bounds.height()) {
- bottom = display_bounds.height();
+ if (bottom >= display_bounds.bottom()) {
+ bottom = display_bounds.bottom();
top = bottom - keyboard_bounds.height();
}
@@ -162,7 +163,11 @@ gfx::Point ContainerFloatingBehavior::GetPositionForShowingKeyboard(
// Make sure that this location is valid according to the current size of the
// screen.
- gfx::Rect keyboard_bounds = gfx::Rect(top_left_offset, keyboard_size);
+ gfx::Rect keyboard_bounds =
+ gfx::Rect(top_left_offset.x() + display_bounds.x(),
+ top_left_offset.y() + display_bounds.y(), keyboard_size.width(),
+ keyboard_size.height());
+
gfx::Rect valid_keyboard_bounds =
ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds);
@@ -175,9 +180,9 @@ bool ContainerFloatingBehavior::IsDragHandle(
return draggable_area_.Contains(offset.x(), offset.y());
}
-void ContainerFloatingBehavior::HandlePointerEvent(
+bool ContainerFloatingBehavior::HandlePointerEvent(
const ui::LocatedEvent& event,
- const gfx::Rect& display_bounds) {
+ const display::Display& current_display) {
// Cannot call UI-backed operations without a KeyboardController
DCHECK(controller_);
auto kb_offset = gfx::Vector2d(event.x(), event.y());
@@ -188,51 +193,90 @@ void ContainerFloatingBehavior::HandlePointerEvent(
// Don't handle events if this runs in a partially initialized state.
if (keyboard_bounds.height() <= 0)
- return;
+ return false;
+
+ ui::PointerId pointer_id = -1;
+ if (event.IsTouchEvent()) {
+ const ui::TouchEvent* te = event.AsTouchEvent();
+ pointer_id = te->pointer_details().id;
+ }
- bool handle_drag = false;
const ui::EventType type = event.type();
- if (IsDragHandle(kb_offset, keyboard_bounds.size())) {
- if (type == ui::ET_TOUCH_PRESSED ||
- (type == ui::ET_MOUSE_PRESSED &&
- ((const ui::MouseEvent*)&event)->IsOnlyLeftMouseButton())) {
- // Drag is starting.
- // Mouse events are limited to just the left mouse button.
-
- drag_started_by_touch_ = (type == ui::ET_TOUCH_PRESSED);
- if (!drag_descriptor_) {
+ switch (type) {
+ case ui::ET_TOUCH_PRESSED:
+ case ui::ET_MOUSE_PRESSED:
+ if (!IsDragHandle(kb_offset, keyboard_bounds.size())) {
+ drag_descriptor_ = nullptr;
+ } else if (type == ui::ET_MOUSE_PRESSED &&
+ !((const ui::MouseEvent*)&event)->IsOnlyLeftMouseButton()) {
+ // Mouse events are limited to just the left mouse button.
+ drag_descriptor_ = nullptr;
+ } else if (!drag_descriptor_) {
// If there is no active drag descriptor, start a new one.
+ bool drag_started_by_touch = (type == ui::ET_TOUCH_PRESSED);
drag_descriptor_.reset(
- new DragDescriptor(keyboard_bounds.origin(), kb_offset));
+ new DragDescriptor(keyboard_bounds.origin(), kb_offset,
+ drag_started_by_touch, pointer_id));
}
- handle_drag = true;
- }
- }
- if (drag_descriptor_ &&
- (type == ui::ET_MOUSE_DRAGGED ||
- (drag_started_by_touch_ && type == ui::ET_TOUCH_MOVED))) {
- // Drag continues.
- // If there is an active drag, use it to determine the new location
- // of the keyboard.
- const gfx::Point original_click_location =
- drag_descriptor_->original_keyboard_location() +
- drag_descriptor_->original_click_offset();
- const gfx::Point current_drag_location =
- keyboard_bounds.origin() + kb_offset;
- const gfx::Vector2d cumulative_drag_offset =
- current_drag_location - original_click_location;
- const gfx::Point new_keyboard_location =
- drag_descriptor_->original_keyboard_location() + cumulative_drag_offset;
- const gfx::Rect new_bounds =
- gfx::Rect(new_keyboard_location, keyboard_bounds.size());
- controller_->MoveKeyboard(new_bounds);
- SavePosition(container->bounds(), display_bounds.size());
- handle_drag = true;
- }
- if (!handle_drag && drag_descriptor_) {
- // drag has ended
- drag_descriptor_ = nullptr;
+ break;
+
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_TOUCH_MOVED:
+ if (!drag_descriptor_) {
+ // do nothing
+ } else if (drag_descriptor_->is_touch_drag() !=
+ (type == ui::ET_TOUCH_MOVED)) {
+ // If the event isn't of the same type that started the drag, end the
+ // drag to prevent confusion.
+ drag_descriptor_ = nullptr;
+ } else if (drag_descriptor_->pointer_id() != pointer_id) {
+ // do nothing.
+ } else {
+ // Drag continues.
+ // If there is an active drag, use it to determine the new location
+ // of the keyboard.
+ const gfx::Point original_click_location =
+ drag_descriptor_->original_keyboard_location() +
+ drag_descriptor_->original_click_offset();
+ const gfx::Point current_drag_location =
+ keyboard_bounds.origin() + kb_offset;
+ const gfx::Vector2d cumulative_drag_offset =
+ current_drag_location - original_click_location;
+ const gfx::Point new_keyboard_location =
+ drag_descriptor_->original_keyboard_location() +
+ cumulative_drag_offset;
+ gfx::Rect new_bounds =
+ gfx::Rect(new_keyboard_location, keyboard_bounds.size());
+
+ DisplayUtil display_util;
+ const display::Display& new_display =
+ display_util.FindAdjacentDisplayIfPointIsNearMargin(
+ current_display, current_drag_location);
+
+ if (current_display.id() == new_display.id()) {
+ controller_->MoveKeyboard(new_bounds);
+ return true;
+ } else {
+ new_bounds =
+ ContainKeyboardToScreenBounds(new_bounds, new_display.bounds());
+ // Since the keyboard has jumped across screens, cancel the current
+ // drag descriptor as though the user has lifted their finger.
+ drag_descriptor_ = nullptr;
+
+ // Enqueue a transition to the adjacent display.
+ // TODO(blakeo): pass new_bounds to display transition.
+ controller_->MoveToDisplayWithTransition(new_display);
+ return true;
+ }
+ SavePosition(container->bounds(), new_display.size());
+ }
+ break;
+
+ default:
+ drag_descriptor_ = nullptr;
+ break;
}
+ return false;
}
void ContainerFloatingBehavior::SetCanonicalBounds(
diff --git a/chromium/ui/keyboard/container_floating_behavior.h b/chromium/ui/keyboard/container_floating_behavior.h
index 6ea2b2abfde..4d3b81bc103 100644
--- a/chromium/ui/keyboard/container_floating_behavior.h
+++ b/chromium/ui/keyboard/container_floating_behavior.h
@@ -43,14 +43,14 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
void InitializeShowAnimationStartingState(aura::Window* container) override;
const gfx::Rect AdjustSetBoundsRequest(
const gfx::Rect& display_bounds,
- const gfx::Rect& requested_bounds) override;
+ const gfx::Rect& requested_bounds_in_screen_coords) override;
bool IsOverscrollAllowed() const override;
bool IsDragHandle(const gfx::Vector2d& offset,
const gfx::Size& keyboard_size) const override;
void SavePosition(const gfx::Rect& keyboard_bounds,
const gfx::Size& screen_size) override;
- void HandlePointerEvent(const ui::LocatedEvent& event,
- const gfx::Rect& display_bounds) override;
+ bool HandlePointerEvent(const ui::LocatedEvent& event,
+ const display::Display& current_display) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
ContainerType GetType() const override;
@@ -84,10 +84,6 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
// Otherwise nullptr.
std::unique_ptr<DragDescriptor> drag_descriptor_ = nullptr;
- // Distinguish whether the current drag is from a touch event or mouse event,
- // so drag/move events can be filtered accordingly
- bool drag_started_by_touch_ = false;
-
gfx::Rect draggable_area_ = gfx::Rect();
};
diff --git a/chromium/ui/keyboard/container_floating_behavior_unittest.cc b/chromium/ui/keyboard/container_floating_behavior_unittest.cc
index 6db3b404566..cc13bd678f9 100644
--- a/chromium/ui/keyboard/container_floating_behavior_unittest.cc
+++ b/chromium/ui/keyboard/container_floating_behavior_unittest.cc
@@ -48,6 +48,13 @@ TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequest) {
workspace.height() - keyboard_height, keyboard_width,
keyboard_height),
result);
+
+ // Try to move the keyboard to the center of the primary display while it's
+ // in a secondary display.
+ gfx::Rect secondary_display(1000, -200, 1200, 800);
+ result = floating_behavior.AdjustSetBoundsRequest(secondary_display, center);
+ // It gets clipped to the far left of this display
+ ASSERT_EQ(gfx::Rect(1000, 100, keyboard_width, keyboard_height), result);
}
TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequestVariousSides) {
diff --git a/chromium/ui/keyboard/container_full_width_behavior.cc b/chromium/ui/keyboard/container_full_width_behavior.cc
index 2dca9c087ec..53071634d9b 100644
--- a/chromium/ui/keyboard/container_full_width_behavior.cc
+++ b/chromium/ui/keyboard/container_full_width_behavior.cc
@@ -58,19 +58,19 @@ void ContainerFullWidthBehavior::InitializeShowAnimationStartingState(
const gfx::Rect ContainerFullWidthBehavior::AdjustSetBoundsRequest(
const gfx::Rect& display_bounds,
- const gfx::Rect& requested_bounds) {
+ const gfx::Rect& requested_bounds_in_screen_coords) {
gfx::Rect new_bounds;
// Honors only the height of the request bounds
- const int keyboard_height = requested_bounds.height();
+ const int keyboard_height = requested_bounds_in_screen_coords.height();
- new_bounds.set_y(display_bounds.height() - keyboard_height);
+ new_bounds.set_y(display_bounds.bottom() - keyboard_height);
new_bounds.set_height(keyboard_height);
// If shelf is positioned on the left side of screen, x is not 0. In
// FULL_WIDTH mode, the virtual keyboard should always align with the left
- // edge of the screen. So manually set x to 0 here.
- new_bounds.set_x(0);
+ // edge of the screen. So manually set x to the left side of the screen.
+ new_bounds.set_x(display_bounds.x());
new_bounds.set_width(display_bounds.width());
return new_bounds;
@@ -93,10 +93,11 @@ bool ContainerFullWidthBehavior::IsDragHandle(
return false;
}
-void ContainerFullWidthBehavior::HandlePointerEvent(
+bool ContainerFullWidthBehavior::HandlePointerEvent(
const ui::LocatedEvent& event,
- const gfx::Rect& display_bounds) {
+ const display::Display& current_display) {
// No-op. Nothing special to do for pointer events.
+ return false;
}
void ContainerFullWidthBehavior::SetCanonicalBounds(
@@ -120,7 +121,10 @@ bool ContainerFullWidthBehavior::BoundsAffectWorkspaceLayout() const {
}
bool ContainerFullWidthBehavior::SetDraggableArea(const gfx::Rect& rect) {
- return false;
+ // Allow extension to call this function but does nothing here.
+ // To avoid unnecessary exception when VK calls this function to
+ // clear draggable area in full width mode.
+ return true;
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/container_full_width_behavior.h b/chromium/ui/keyboard/container_full_width_behavior.h
index 077d3b92eb6..661d471d43a 100644
--- a/chromium/ui/keyboard/container_full_width_behavior.h
+++ b/chromium/ui/keyboard/container_full_width_behavior.h
@@ -35,14 +35,14 @@ class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior {
void InitializeShowAnimationStartingState(aura::Window* container) override;
const gfx::Rect AdjustSetBoundsRequest(
const gfx::Rect& display_bounds,
- const gfx::Rect& requested_bounds) override;
+ const gfx::Rect& requested_bounds_in_screen_coords) override;
bool IsOverscrollAllowed() const override;
bool IsDragHandle(const gfx::Vector2d& offset,
const gfx::Size& keyboard_size) const override;
void SavePosition(const gfx::Rect& keyboard_bounds,
const gfx::Size& screen_size) override;
- void HandlePointerEvent(const ui::LocatedEvent& event,
- const gfx::Rect& display_bounds) override;
+ bool HandlePointerEvent(const ui::LocatedEvent& event,
+ const display::Display& current_display) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
ContainerType GetType() const override;
diff --git a/chromium/ui/keyboard/container_full_width_behavior_unittest.cc b/chromium/ui/keyboard/container_full_width_behavior_unittest.cc
index 76e93843efd..eaceffb775e 100644
--- a/chromium/ui/keyboard/container_full_width_behavior_unittest.cc
+++ b/chromium/ui/keyboard/container_full_width_behavior_unittest.cc
@@ -18,20 +18,22 @@ class ContainerFullWidthBehaviorTest : public testing::Test {
TEST(ContainerFullWidthBehaviorTest, AdjustSetBoundsRequest) {
ContainerFullWidthBehavior full_width_behavior(nullptr);
- gfx::Rect workspace(0, 0, 300, 200);
+ // workspace is not always necessarily positioned at the origin (e.g.
+ // secondary display).
+ gfx::Rect workspace(20, -30, 300, 200);
gfx::Rect requested_bounds(0, 0, 10, 10);
gfx::Rect result;
// Ignore width. Stretch the bounds across the bottom of the screen.
result =
full_width_behavior.AdjustSetBoundsRequest(workspace, requested_bounds);
- ASSERT_EQ(gfx::Rect(0, 190, 300, 10), result);
+ ASSERT_EQ(gfx::Rect(20, 160, 300, 10), result);
// Even if the coordinates are non-zero, ignore them. Only use height.
requested_bounds = gfx::Rect(30, 80, 20, 100);
result =
full_width_behavior.AdjustSetBoundsRequest(workspace, requested_bounds);
- ASSERT_EQ(gfx::Rect(0, 100, 300, 100), result);
+ ASSERT_EQ(gfx::Rect(20, 70, 300, 100), result);
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/content/keyboard.cc b/chromium/ui/keyboard/content/keyboard.cc
deleted file mode 100644
index 4f7da4d2daa..00000000000
--- a/chromium/ui/keyboard/content/keyboard.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/keyboard/content/keyboard.h"
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace keyboard {
-
-void InitializeKeyboard() {
- static bool initialized = false;
- if (initialized)
- return;
- initialized = true;
-
- base::FilePath pak_dir;
- PathService::Get(base::DIR_MODULE, &pak_dir);
- base::FilePath pak_file = pak_dir.Append(
- FILE_PATH_LITERAL("keyboard_resources.pak"));
- ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
- pak_file, ui::SCALE_FACTOR_100P);
-}
-
-} // namespace keyboard
diff --git a/chromium/ui/keyboard/content/keyboard.h b/chromium/ui/keyboard/content/keyboard.h
deleted file mode 100644
index 0878b7b90e7..00000000000
--- a/chromium/ui/keyboard/content/keyboard.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_KEYBOARD_KEYBOARD_H_
-#define UI_KEYBOARD_KEYBOARD_H_
-
-#include "ui/keyboard/keyboard_export.h"
-
-namespace keyboard {
-
-// Initializes the keyboard module. This includes adding the necessary pak files
-// for loading resources used in for the virtual keyboard. This becomes a no-op
-// after the first call.
-KEYBOARD_EXPORT void InitializeKeyboard();
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_KEYBOARD_H_
diff --git a/chromium/ui/keyboard/content/keyboard_constants.cc b/chromium/ui/keyboard/content/keyboard_constants.cc
deleted file mode 100644
index 449f96f4127..00000000000
--- a/chromium/ui/keyboard/content/keyboard_constants.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/keyboard/content/keyboard_constants.h"
-
-namespace keyboard {
-
-const char kKeyboardURL[] = "chrome://keyboard";
-const char kKeyboardHost[] = "keyboard";
-
-} // namespace keyboard
diff --git a/chromium/ui/keyboard/content/keyboard_constants.h b/chromium/ui/keyboard/content/keyboard_constants.h
deleted file mode 100644
index 6c4e6612b11..00000000000
--- a/chromium/ui/keyboard/content/keyboard_constants.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_KEYBOARD_CONTENT_KEYBOARD_CONSTANTS_H_
-#define UI_KEYBOARD_CONTENT_KEYBOARD_CONSTANTS_H_
-
-#include "ui/keyboard/keyboard_export.h"
-
-namespace keyboard {
-
-// The URL of the keyboard extension.
-KEYBOARD_EXPORT extern const char kKeyboardURL[];
-
-// The host of the keyboard extension URL.
-KEYBOARD_EXPORT extern const char kKeyboardHost[];
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_CONTENT_KEYBOARD_CONSTANTS_H_
diff --git a/chromium/ui/keyboard/content/keyboard_content_util.h b/chromium/ui/keyboard/content/keyboard_content_util.h
deleted file mode 100644
index e96cdfe3e93..00000000000
--- a/chromium/ui/keyboard/content/keyboard_content_util.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_KEYBOARD_CONTENT_KEYBOARD_COTNENT_UTIL_H_
-#define UI_KEYBOARD_CONTENT_KEYBOARD_COTNENT_UTIL_H_
-
-#include <stddef.h>
-
-#include "base/strings/string16.h"
-#include "ui/keyboard/keyboard_export.h"
-
-class GURL;
-
-struct GritResourceMap;
-
-namespace keyboard {
-
-// Sets the override content url.
-// This is used by for input view for extension IMEs.
-KEYBOARD_EXPORT void SetOverrideContentUrl(const GURL& url);
-
-// Gets the override content url.
-KEYBOARD_EXPORT const GURL& GetOverrideContentUrl();
-
-// Get the list of keyboard resources. |size| is populated with the number of
-// resources in the returned array.
-KEYBOARD_EXPORT const GritResourceMap* GetKeyboardExtensionResources(
- size_t* size);
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_CONTENT_KEYBOARD_COTNENT_UTIL_H_
diff --git a/chromium/ui/keyboard/display_util.cc b/chromium/ui/keyboard/display_util.cc
new file mode 100644
index 00000000000..d1431387fde
--- /dev/null
+++ b/chromium/ui/keyboard/display_util.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/keyboard/display_util.h"
+
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/display/types/display_constants.h"
+
+namespace {
+
+constexpr int kWindowMargin = 10;
+
+} // namespace
+
+namespace keyboard {
+
+DisplayUtil::DisplayUtil() {}
+
+int64_t DisplayUtil::GetNearestDisplayIdToWindow(aura::Window* window) const {
+ return GetNearestDisplayToWindow(window).id();
+}
+
+display::Display DisplayUtil::GetNearestDisplayToWindow(
+ aura::Window* window) const {
+ return display::Screen::GetScreen()->GetDisplayNearestWindow(window);
+}
+
+display::Display DisplayUtil::FindAdjacentDisplayIfPointIsNearMargin(
+ const display::Display& current_display,
+ const gfx::Point& point_in_local) const {
+ const gfx::Rect current_bounds = current_display.bounds();
+
+ const gfx::Point point =
+ point_in_local + current_display.bounds().origin().OffsetFromOrigin();
+
+ int representative_x = point.x();
+ int representative_y = point.y();
+
+ int current_left = current_bounds.x();
+ int current_right = current_left + current_bounds.width();
+ int current_top = current_bounds.y();
+ int current_bottom = current_top + current_bounds.height();
+
+ // If the point is close to
+ if (point.x() - current_left <= kWindowMargin) {
+ representative_x = current_left - kWindowMargin;
+ } else if (current_right - point.x() <= kWindowMargin) {
+ representative_x = current_right + kWindowMargin;
+ } else if (point.y() - current_top <= kWindowMargin) {
+ representative_y = current_top - kWindowMargin;
+ } else if (current_bottom - point.y() <= kWindowMargin) {
+ representative_y = current_bottom + kWindowMargin;
+ } else {
+ return current_display;
+ }
+
+ for (const display::Display& display :
+ display::Screen::GetScreen()->GetAllDisplays()) {
+ const gfx::Rect& new_bounds = display.work_area();
+ if (display.touch_support() == display::Display::TouchSupport::AVAILABLE &&
+ display.id() != current_display.id() &&
+ new_bounds.Contains(representative_x, representative_y)) {
+ return display;
+ }
+ }
+ return current_display;
+}
+
+} // namespace keyboard
diff --git a/chromium/ui/keyboard/display_util.h b/chromium/ui/keyboard/display_util.h
new file mode 100644
index 00000000000..8d4faf6dbeb
--- /dev/null
+++ b/chromium/ui/keyboard/display_util.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_KEYBOARD_DISPLAY_UTIL_H_
+#define UI_KEYBOARD_DISPLAY_UTIL_H_
+
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+
+namespace keyboard {
+
+// Helper class for querying information about the screen.
+class DisplayUtil {
+ public:
+ DisplayUtil();
+
+ int64_t GetNearestDisplayIdToWindow(aura::Window* window) const;
+ display::Display GetNearestDisplayToWindow(aura::Window* window) const;
+ display::Display FindAdjacentDisplayIfPointIsNearMargin(
+ const display::Display& current_display,
+ const gfx::Point& point) const;
+};
+
+} // namespace keyboard
+
+#endif // UI_KEYBOARD_DISPLAY_UTIL_H_
diff --git a/chromium/ui/keyboard/drag_descriptor.cc b/chromium/ui/keyboard/drag_descriptor.cc
index e15d5fd5d1c..edadab99ab4 100644
--- a/chromium/ui/keyboard/drag_descriptor.cc
+++ b/chromium/ui/keyboard/drag_descriptor.cc
@@ -4,14 +4,19 @@
#include "ui/keyboard/drag_descriptor.h"
+#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d.h"
namespace keyboard {
DragDescriptor::DragDescriptor(const gfx::Point& keyboard_location,
- const gfx::Vector2d& click_offset)
+ const gfx::Vector2d& click_offset,
+ bool is_touch_drag,
+ ui::PointerId pointer_id)
: original_keyboard_location_(keyboard_location),
- original_click_offset_(click_offset) {}
+ original_click_offset_(click_offset),
+ is_touch_drag_(is_touch_drag),
+ pointer_id_(pointer_id) {}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/drag_descriptor.h b/chromium/ui/keyboard/drag_descriptor.h
index a40ab226e5f..ff792096d76 100644
--- a/chromium/ui/keyboard/drag_descriptor.h
+++ b/chromium/ui/keyboard/drag_descriptor.h
@@ -5,6 +5,7 @@
#ifndef UI_KEYBOARD_DRAG_DESCRIPTOR_H_
#define UI_KEYBOARD_DRAG_DESCRIPTOR_H_
+#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -18,16 +19,28 @@ namespace keyboard {
class DragDescriptor {
public:
DragDescriptor(const gfx::Point& keyboard_location,
- const gfx::Vector2d& click_offset);
+ const gfx::Vector2d& click_offset,
+ bool is_touch_drag,
+ ui::PointerId pointer_id);
gfx::Point original_keyboard_location() const {
return original_keyboard_location_;
}
gfx::Vector2d original_click_offset() const { return original_click_offset_; }
+ bool is_touch_drag() { return is_touch_drag_; }
+ ui::PointerId pointer_id() { return pointer_id_; }
private:
const gfx::Point original_keyboard_location_;
const gfx::Vector2d original_click_offset_;
+
+ // Distinguish whether the current drag is from a touch event or mouse event,
+ // so drag/move events can be filtered accordingly
+ const bool is_touch_drag_;
+
+ // The pointer ID provided by the touch event to disambiguate multiple
+ // touch points. If this is a mouse event, then this value is -1.
+ const ui::PointerId pointer_id_;
};
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc
index b9ba7f519ef..9c595718d6c 100644
--- a/chromium/ui/keyboard/keyboard_controller.cc
+++ b/chromium/ui/keyboard/keyboard_controller.cc
@@ -23,8 +23,6 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/rect.h"
@@ -33,12 +31,14 @@
#include "ui/keyboard/container_floating_behavior.h"
#include "ui/keyboard/container_full_width_behavior.h"
#include "ui/keyboard/container_type.h"
+#include "ui/keyboard/display_util.h"
#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/keyboard/keyboard_layout_manager.h"
#include "ui/keyboard/keyboard_ui.h"
#include "ui/keyboard/keyboard_util.h"
#include "ui/keyboard/notification_manager.h"
#include "ui/keyboard/queued_container_type.h"
+#include "ui/keyboard/queued_display_change.h"
#include "ui/wm/core/window_animations.h"
#if defined(OS_CHROMEOS)
@@ -309,11 +309,8 @@ void KeyboardController::SetContainerBounds(const gfx::Rect& new_bounds,
if (keyboard_locked()) {
// Do not move the keyboard to another display after switch to an IME in
// a different extension.
- const int64_t display_id =
- display::Screen::GetScreen()
- ->GetDisplayNearestWindow(GetContainerWindow())
- .id();
- ShowKeyboardInDisplay(display_id);
+ ShowKeyboardInDisplay(
+ display_util_.GetNearestDisplayIdToWindow(GetContainerWindow()));
} else {
ShowKeyboard(false /* lock */);
}
@@ -340,6 +337,11 @@ void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
observer_list_.RemoveObserver(observer);
}
+void KeyboardController::MoveToDisplayWithTransition(display::Display display) {
+ queued_display_change_ = std::make_unique<QueuedDisplayChange>(display);
+ HideKeyboard(HIDE_REASON_AUTOMATIC);
+}
+
void KeyboardController::HideKeyboard(HideReason reason) {
TRACE_EVENT0("vk", "HideKeyboard");
@@ -394,12 +396,30 @@ void KeyboardController::HideKeyboard(HideReason reason) {
}
void KeyboardController::HideAnimationFinished() {
- if (state_ == KeyboardControllerState::HIDDEN && queued_container_type_) {
- SetContainerBehaviorInternal(queued_container_type_->container_type());
- ShowKeyboard(false /* lock */);
+ if (state_ == KeyboardControllerState::HIDDEN) {
+ if (queued_container_type_) {
+ SetContainerBehaviorInternal(queued_container_type_->container_type());
+ // The position of the container window will be adjusted shortly in
+ // |PopulateKeyboardContent| before showing animation, so we can set the
+ // passed bounds directly.
+ if (queued_container_type_->target_bounds())
+ SetContainerBounds(queued_container_type_->target_bounds().value(),
+ false /* contents_loaded */);
+ ShowKeyboard(false /* lock */);
+ }
+
+ if (queued_display_change_) {
+ ShowKeyboardInDisplay(queued_display_change_->new_display().id());
+ queued_display_change_ = nullptr;
+ }
}
}
+void KeyboardController::ShowAnimationFinished() {
+ MarkKeyboardLoadFinished();
+ NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea();
+}
+
void KeyboardController::SetContainerBehaviorInternal(
const ContainerType type) {
switch (type) {
@@ -642,8 +662,9 @@ void KeyboardController::PopulateKeyboardContent(int64_t display_id,
ui_->ShowKeyboardContainer(container_.get());
- animation_observer_ = std::make_unique<CallbackAnimationObserver>(
- base::BindOnce(&MarkKeyboardLoadFinished));
+ animation_observer_ =
+ std::make_unique<CallbackAnimationObserver>(base::BindOnce(
+ &KeyboardController::ShowAnimationFinished, base::Unretained(this)));
ui::ScopedLayerAnimationSettings settings(container_animator);
settings.AddObserver(animation_observer_.get());
@@ -654,7 +675,6 @@ void KeyboardController::PopulateKeyboardContent(int64_t display_id,
queued_container_type_ = nullptr;
ChangeState(KeyboardControllerState::SHOWN);
- NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea();
}
bool KeyboardController::WillHideKeyboard() const {
@@ -772,14 +792,15 @@ bool KeyboardController::IsOverscrollAllowed() const {
return container_behavior_->IsOverscrollAllowed();
}
-void KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) {
- container_behavior_->HandlePointerEvent(
- event, container_->GetRootWindow()->bounds());
+bool KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) {
+ const display::Display& current_display =
+ display_util_.GetNearestDisplayToWindow(container_->GetRootWindow());
+ return container_behavior_->HandlePointerEvent(event, current_display);
}
-
void KeyboardController::SetContainerType(
const ContainerType type,
+ base::Optional<gfx::Rect> target_bounds,
base::OnceCallback<void(bool)> callback) {
if (container_behavior_->GetType() == type) {
std::move(callback).Run(false);
@@ -789,13 +810,15 @@ void KeyboardController::SetContainerType(
if (state_ == KeyboardControllerState::SHOWN) {
// Keyboard is already shown. Hiding the keyboard at first then switching
// container type.
- queued_container_type_ =
- std::make_unique<QueuedContainerType>(this, type, std::move(callback));
+ queued_container_type_ = std::make_unique<QueuedContainerType>(
+ this, type, target_bounds, std::move(callback));
HideKeyboard(HIDE_REASON_AUTOMATIC);
} else {
// Keyboard is hidden. Switching the container type immediately and invoking
// the passed callback now.
SetContainerBehaviorInternal(type);
+ if (target_bounds)
+ SetContainerBounds(target_bounds.value(), false /* contents_loaded */);
DCHECK(GetActiveContainerType() == type);
std::move(callback).Run(true /* change_successful */);
}
diff --git a/chromium/ui/keyboard/keyboard_controller.h b/chromium/ui/keyboard/keyboard_controller.h
index ef9356317a4..1b3d2ceb125 100644
--- a/chromium/ui/keyboard/keyboard_controller.h
+++ b/chromium/ui/keyboard/keyboard_controller.h
@@ -18,12 +18,14 @@
#include "ui/gfx/geometry/vector2d.h"
#include "ui/keyboard/container_behavior.h"
#include "ui/keyboard/container_type.h"
+#include "ui/keyboard/display_util.h"
#include "ui/keyboard/keyboard_event_filter.h"
#include "ui/keyboard/keyboard_export.h"
#include "ui/keyboard/keyboard_layout_delegate.h"
#include "ui/keyboard/keyboard_util.h"
#include "ui/keyboard/notification_manager.h"
#include "ui/keyboard/queued_container_type.h"
+#include "ui/keyboard/queued_display_change.h"
namespace aura {
class Window;
@@ -168,7 +170,7 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// Handle mouse and touch events on the keyboard. The effects of this method
// will not stop propagation to the keyboard extension.
- void HandlePointerEvent(const ui::LocatedEvent& event);
+ bool HandlePointerEvent(const ui::LocatedEvent& event);
// Moves an already loaded keyboard.
void MoveKeyboard(const gfx::Rect new_bounds);
@@ -177,11 +179,14 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// will trigger a hide animation and a subsequent show animation. Otherwise
// the ContainerBehavior change is synchronous.
void SetContainerType(const ContainerType type,
+ base::Optional<gfx::Rect> target_bounds,
base::OnceCallback<void(bool)> callback);
// Sets floating keyboard drggable rect.
bool SetDraggableArea(const gfx::Rect& rect);
+ void MoveToDisplayWithTransition(display::Display display);
+
private:
// For access to Observer methods for simulation.
friend class KeyboardControllerTest;
@@ -224,8 +229,10 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// Returns true if keyboard is scheduled to hide.
bool WillHideKeyboard() const;
- // Called when the hide animation finishes.
+ // Called when the hide animation finished.
void HideAnimationFinished();
+ // Called when the show animation finished.
+ void ShowAnimationFinished();
void NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea();
@@ -264,6 +271,7 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
std::unique_ptr<ContainerBehavior> container_behavior_;
std::unique_ptr<QueuedContainerType> queued_container_type_;
+ std::unique_ptr<QueuedDisplayChange> queued_display_change_;
// If true, show the keyboard window when keyboard UI content updates.
bool show_on_content_update_;
@@ -285,6 +293,8 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
base::Time time_of_last_blur_ = base::Time::UnixEpoch();
+ DisplayUtil display_util_;
+
static KeyboardController* instance_;
base::WeakPtrFactory<KeyboardController> weak_factory_report_lingering_state_;
diff --git a/chromium/ui/keyboard/keyboard_controller_unittest.cc b/chromium/ui/keyboard/keyboard_controller_unittest.cc
index 8ecafe94069..45793d12b79 100644
--- a/chromium/ui/keyboard/keyboard_controller_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_controller_unittest.cc
@@ -8,7 +8,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
@@ -385,45 +384,6 @@ TEST_F(KeyboardControllerTest, KeyboardSize) {
VerifyKeyboardWindowSize(container, keyboard);
}
-// Flaky on Windows. See http://crbug.com/757044
-#if defined(OS_WIN)
-#define MAYBE_KeyboardSizeMultiRootWindow DISABLED_KeyboardSizeMultiRootWindow
-#else
-#define MAYBE_KeyboardSizeMultiRootWindow KeyboardSizeMultiRootWindow
-#endif
-
-TEST_F(KeyboardControllerTest, MAYBE_KeyboardSizeMultiRootWindow) {
- aura::Window* container(controller()->GetContainerWindow());
- aura::Window* keyboard(ui()->GetContentsWindow());
- gfx::Rect screen_bounds = root_window()->bounds();
- root_window()->AddChild(container);
- container->AddChild(keyboard);
- const gfx::Rect& initial_bounds = container->bounds();
- // The container should be positioned at the bottom of screen and has 0
- // height.
- ASSERT_EQ(0, initial_bounds.height());
- ASSERT_EQ(screen_bounds.height(), initial_bounds.y());
- VerifyKeyboardWindowSize(container, keyboard);
-
- // Adding new root window.
- std::unique_ptr<aura::WindowTreeHost> secondary_tree_host =
- base::WrapUnique<aura::WindowTreeHost>(
- aura::WindowTreeHost::Create(gfx::Rect(0, 0, 1000, 500)));
- secondary_tree_host->InitHost();
- EXPECT_EQ(1000, secondary_tree_host->window()->bounds().width());
- EXPECT_EQ(500, secondary_tree_host->window()->bounds().height());
-
- // Move the keyboard into the secondary root window.
- controller()->HideKeyboard(
- KeyboardController::HideReason::HIDE_REASON_AUTOMATIC);
- root_window()->RemoveChild(container);
- secondary_tree_host->window()->AddChild(container);
-
- const gfx::Rect& new_bounds = container->bounds();
- EXPECT_EQ(500, new_bounds.y());
- VerifyKeyboardWindowSize(container, keyboard);
-}
-
// Tests that tapping/clicking inside the keyboard does not give it focus.
TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler;
@@ -709,11 +669,11 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
gfx::Transform transform;
transform.Translate(0, keyboard::kFullWidthKeyboardAnimationDistance);
EXPECT_EQ(transform, layer->transform());
- // animation occurs in a cloned layer, so the actual final bounds should
- // already be applied to the container.
- EXPECT_EQ(keyboard_container()->bounds(), notified_visible_bounds());
- EXPECT_EQ(keyboard_container()->bounds(), notified_occluding_bounds());
- EXPECT_TRUE(notified_is_available());
+ // Actual final bounds should be notified after animation finishes to avoid
+ // flash of background being seen.
+ EXPECT_EQ(gfx::Rect(), notified_visible_bounds());
+ EXPECT_EQ(gfx::Rect(), notified_occluding_bounds());
+ EXPECT_FALSE(notified_is_available());
RunAnimationForLayer(layer);
EXPECT_TRUE(keyboard_container()->IsVisible());
@@ -751,7 +711,7 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
EXPECT_FALSE(notified_is_available());
SetModeCallbackInvocationCounter invocation_counter;
- controller()->SetContainerType(ContainerType::FLOATING,
+ controller()->SetContainerType(ContainerType::FLOATING, base::nullopt,
invocation_counter.GetInvocationCallback());
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true));
EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false));
@@ -767,12 +727,44 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
// callback should do nothing when container mode is set to the current active
// container type. An unnecessary call gets registered synchronously as a
// failure status to the callback.
- controller()->SetContainerType(ContainerType::FLOATING,
+ controller()->SetContainerType(ContainerType::FLOATING, base::nullopt,
invocation_counter.GetInvocationCallback());
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true));
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(false));
}
+TEST_F(KeyboardControllerAnimationTest, ChangeContainerModeWithBounds) {
+ ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler;
+ SetModeCallbackInvocationCounter invocation_counter;
+
+ ui::Layer* layer = keyboard_container()->layer();
+ ShowKeyboard();
+ RunAnimationForLayer(layer);
+ EXPECT_EQ(ContainerType::FULL_WIDTH, controller()->GetActiveContainerType());
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(contents_window()->IsVisible());
+
+ // Changing the mode to another mode invokes hiding + showing.
+ const gfx::Rect target_bounds(0, 0, 1200, 600);
+ controller()->SetContainerType(ContainerType::FLOATING,
+ base::make_optional(target_bounds),
+ invocation_counter.GetInvocationCallback());
+ // The container window shouldn't be resized until it's hidden even if the
+ // target bounds is passed to |SetContainerType|.
+ EXPECT_EQ(gfx::Rect(), notified_visible_bounds());
+ EXPECT_EQ(0, invocation_counter.invocation_count_for_status(true));
+ EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false));
+ RunAnimationForLayer(layer);
+ // Hiding animation finished. The container window should be resized to the
+ // target bounds.
+ EXPECT_EQ(keyboard_container()->bounds().size(), target_bounds.size());
+ // Then showing animation automatically start.
+ layer = keyboard_container()->layer();
+ RunAnimationForLayer(layer);
+ EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true));
+ EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false));
+}
+
// Show keyboard during keyboard hide animation should abort the hide animation
// and the keyboard should animate in.
// Test for crbug.com/333284.
diff --git a/chromium/ui/keyboard/keyboard_event_filter.cc b/chromium/ui/keyboard/keyboard_event_filter.cc
index 47dd5040809..25ea969b750 100644
--- a/chromium/ui/keyboard/keyboard_event_filter.cc
+++ b/chromium/ui/keyboard/keyboard_event_filter.cc
@@ -23,17 +23,17 @@ void KeyboardEventFilter::OnGestureEvent(ui::GestureEvent* event) {
}
void KeyboardEventFilter::OnMouseEvent(ui::MouseEvent* event) {
- ProcessPointerEvent(*event);
+ ProcessPointerEvent(event);
}
void KeyboardEventFilter::OnTouchEvent(ui::TouchEvent* event) {
- ProcessPointerEvent(*event);
+ ProcessPointerEvent(event);
}
-void KeyboardEventFilter::ProcessPointerEvent(const ui::LocatedEvent& event) {
+void KeyboardEventFilter::ProcessPointerEvent(ui::LocatedEvent* event) {
KeyboardController* controller = KeyboardController::GetInstance();
- if (controller)
- controller->HandlePointerEvent(event);
+ if (controller && controller->HandlePointerEvent(*event))
+ event->SetHandled();
}
} // nemespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_event_filter.h b/chromium/ui/keyboard/keyboard_event_filter.h
index 3be7e45e20d..d3201328f13 100644
--- a/chromium/ui/keyboard/keyboard_event_filter.h
+++ b/chromium/ui/keyboard/keyboard_event_filter.h
@@ -25,7 +25,7 @@ class KEYBOARD_EXPORT KeyboardEventFilter : public ui::EventHandler {
void OnMouseEvent(ui::MouseEvent* event) override;
private:
- void ProcessPointerEvent(const ui::LocatedEvent& event);
+ void ProcessPointerEvent(ui::LocatedEvent* event);
DISALLOW_COPY_AND_ASSIGN(KeyboardEventFilter);
};
diff --git a/chromium/ui/keyboard/keyboard_layout_manager.cc b/chromium/ui/keyboard/keyboard_layout_manager.cc
index 8323fa1108b..237291fb70b 100644
--- a/chromium/ui/keyboard/keyboard_layout_manager.cc
+++ b/chromium/ui/keyboard/keyboard_layout_manager.cc
@@ -5,6 +5,7 @@
#include "ui/keyboard/keyboard_layout_manager.h"
#include "ui/compositor/layer_animator.h"
+#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_util.h"
@@ -36,20 +37,29 @@ void KeyboardLayoutManager::SetChildBounds(aura::Window* child,
// resized and covers the container window. Note the contents' bound is only
// set in OnWindowResized.
- const aura::Window* root_window =
+ aura::Window* root_window =
controller_->GetContainerWindow()->GetRootWindow();
// If the keyboard has been deactivated, this reference will be null.
if (!root_window)
return;
- const gfx::Rect new_bounds = controller_->AdjustSetBoundsRequest(
- root_window->bounds(), requested_bounds);
+ DisplayUtil display_util;
+ const display::Display& display =
+ display_util.GetNearestDisplayToWindow(root_window);
+ const gfx::Vector2d display_offset =
+ display.bounds().origin().OffsetFromOrigin();
+
+ const gfx::Rect new_bounds =
+ controller_->AdjustSetBoundsRequest(display.bounds(),
+ requested_bounds + display_offset) -
+ display_offset;
// Containar bounds should only be reset when the contents window bounds
// actually change. Otherwise it interrupts the initial animation of showing
// the keyboard. Described in crbug.com/356753.
gfx::Rect old_bounds = contents_window_->GetTargetBounds();
+
aura::Window::ConvertRectToTarget(contents_window_, root_window, &old_bounds);
if (new_bounds == old_bounds)
return;
diff --git a/chromium/ui/keyboard/content/keyboard_content_util.cc b/chromium/ui/keyboard/keyboard_resource_util.cc
index aec8659d455..70beddcd9c6 100644
--- a/chromium/ui/keyboard/content/keyboard_content_util.cc
+++ b/chromium/ui/keyboard/keyboard_resource_util.cc
@@ -1,30 +1,20 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/keyboard/content/keyboard_content_util.h"
+#include "ui/keyboard/keyboard_resource_util.h"
-#include "base/lazy_instance.h"
+#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/path_service.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/keyboard/grit/keyboard_resources.h"
#include "ui/keyboard/grit/keyboard_resources_map.h"
-#include "url/gurl.h"
namespace keyboard {
-namespace {
-base::LazyInstance<GURL>::DestructorAtExit g_override_content_url =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-void SetOverrideContentUrl(const GURL& url) {
- g_override_content_url.Get() = url;
-}
-
-const GURL& GetOverrideContentUrl() {
- return g_override_content_url.Get();
-}
+const char kKeyboardURL[] = "chrome://keyboard";
+const char kKeyboardHost[] = "keyboard";
const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
// This looks a lot like the contents of a resource map; however it is
@@ -107,4 +97,18 @@ const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
return kKeyboardResources;
}
+void InitializeKeyboardResources() {
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+
+ base::FilePath pak_dir;
+ PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::FilePath pak_file =
+ pak_dir.Append(FILE_PATH_LITERAL("keyboard_resources.pak"));
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ pak_file, ui::SCALE_FACTOR_100P);
+}
+
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_resource_util.h b/chromium/ui/keyboard/keyboard_resource_util.h
new file mode 100644
index 00000000000..b10dcc575fe
--- /dev/null
+++ b/chromium/ui/keyboard/keyboard_resource_util.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
+#define UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
+
+#include <stddef.h>
+
+#include "ui/keyboard/keyboard_export.h"
+
+struct GritResourceMap;
+
+namespace keyboard {
+
+// The URL of the keyboard extension.
+KEYBOARD_EXPORT extern const char kKeyboardURL[];
+
+// The host of the keyboard extension URL.
+KEYBOARD_EXPORT extern const char kKeyboardHost[];
+
+// Get the list of keyboard resources. |size| is populated with the number of
+// resources in the returned array.
+KEYBOARD_EXPORT const GritResourceMap* GetKeyboardExtensionResources(
+ size_t* size);
+
+// Initializes the keyboard module. This includes adding the necessary pak files
+// for loading resources used in for the virtual keyboard. This becomes a no-op
+// after the first call.
+KEYBOARD_EXPORT void InitializeKeyboardResources();
+
+} // namespace keyboard
+
+#endif // UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
diff --git a/chromium/ui/keyboard/keyboard_resources.grd b/chromium/ui/keyboard/keyboard_resources.grd
index 60ee41edaf0..91ca2ba2c94 100644
--- a/chromium/ui/keyboard/keyboard_resources.grd
+++ b/chromium/ui/keyboard/keyboard_resources.grd
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
NOTE: if you are adding resources here, you should probably also edit:
- ui/keyboard/keyboard_ui_controller.cc
- ui/keyboard/keyboard_util.cc
+ ui/keyboard/keyboard_resource_util.cc
-->
<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
diff --git a/chromium/ui/keyboard/keyboard_util_unittest.cc b/chromium/ui/keyboard/keyboard_util_unittest.cc
index bcbc714b6ef..a4f4eb8a28a 100644
--- a/chromium/ui/keyboard/keyboard_util_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_util_unittest.cc
@@ -5,7 +5,6 @@
#include "ui/keyboard/keyboard_util.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_test_util.h"
diff --git a/chromium/ui/keyboard/queued_container_type.cc b/chromium/ui/keyboard/queued_container_type.cc
index 2cf7b882e24..d876b45c1ab 100644
--- a/chromium/ui/keyboard/queued_container_type.cc
+++ b/chromium/ui/keyboard/queued_container_type.cc
@@ -10,9 +10,11 @@ namespace keyboard {
QueuedContainerType::QueuedContainerType(
KeyboardController* controller,
ContainerType container_type,
+ base::Optional<gfx::Rect> bounds,
base::OnceCallback<void(bool success)> callback)
: controller_(controller),
container_type_(container_type),
+ bounds_(bounds),
callback_(std::move(callback)){};
QueuedContainerType::~QueuedContainerType() {
diff --git a/chromium/ui/keyboard/queued_container_type.h b/chromium/ui/keyboard/queued_container_type.h
index ce58d930e28..aa678cd9ec6 100644
--- a/chromium/ui/keyboard/queued_container_type.h
+++ b/chromium/ui/keyboard/queued_container_type.h
@@ -6,6 +6,8 @@
#define UI_KEYBOARD_QUEUED_CONTAINER_TYPE_H_
#include "base/bind.h"
+#include "base/optional.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/keyboard/container_type.h"
namespace keyboard {
@@ -22,13 +24,16 @@ class QueuedContainerType {
public:
QueuedContainerType(KeyboardController* controller,
ContainerType container_type,
+ base::Optional<gfx::Rect> bounds,
base::OnceCallback<void(bool success)> callback);
~QueuedContainerType();
ContainerType container_type() { return container_type_; }
+ base::Optional<gfx::Rect> target_bounds() { return bounds_; }
private:
KeyboardController* controller_;
ContainerType container_type_;
+ base::Optional<gfx::Rect> bounds_;
base::OnceCallback<void(bool success)> callback_;
};
diff --git a/chromium/ui/keyboard/queued_display_change.cc b/chromium/ui/keyboard/queued_display_change.cc
new file mode 100644
index 00000000000..ccc1d2f1973
--- /dev/null
+++ b/chromium/ui/keyboard/queued_display_change.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/keyboard/queued_display_change.h"
+#include "base/bind.h"
+#include "ui/display/display.h"
+#include "ui/keyboard/keyboard_controller.h"
+
+namespace keyboard {
+
+QueuedDisplayChange::QueuedDisplayChange(const display::Display& display)
+ : new_display_(display){};
+
+QueuedDisplayChange::~QueuedDisplayChange(){};
+
+} // namespace keyboard
diff --git a/chromium/ui/keyboard/queued_display_change.h b/chromium/ui/keyboard/queued_display_change.h
new file mode 100644
index 00000000000..527a0df98aa
--- /dev/null
+++ b/chromium/ui/keyboard/queued_display_change.h
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_KEYBOARD_QUEUED_DISPLAY_CHANGE_H_
+#define UI_KEYBOARD_QUEUED_DISPLAY_CHANGE_H_
+
+#include "base/bind.h"
+#include "base/optional.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/keyboard/container_type.h"
+
+namespace keyboard {
+
+// TODO: refactor and merge this into QueuedContainerType and rename it to
+// something like QueuedVisualChange or similar.
+class QueuedDisplayChange {
+ public:
+ QueuedDisplayChange(const display::Display& display_info);
+ ~QueuedDisplayChange();
+
+ display::Display new_display() { return new_display_; }
+
+ private:
+ display::Display new_display_;
+};
+
+} // namespace keyboard
+
+#endif // UI_KEYBOARD_QUEUED_DISPLAY_CHANGE_H_
diff --git a/chromium/ui/latency/BUILD.gn b/chromium/ui/latency/BUILD.gn
index e5abf3bd958..2aeebd991ae 100644
--- a/chromium/ui/latency/BUILD.gn
+++ b/chromium/ui/latency/BUILD.gn
@@ -7,11 +7,19 @@ import("//testing/test.gni")
jumbo_source_set("latency") {
sources = [
+ "fixed_point.cc",
+ "fixed_point.h",
+ "histograms.cc",
+ "histograms.h",
"latency_histogram_macros.h",
"latency_info.cc",
"latency_info.h",
"latency_tracker.cc",
"latency_tracker.h",
+ "stream_analyzer.cc",
+ "stream_analyzer.h",
+ "windowed_analyzer.cc",
+ "windowed_analyzer.h",
]
deps = [
@@ -37,7 +45,13 @@ jumbo_source_set("test_support") {
test("latency_unittests") {
sources = [
+ "fixed_point_unittest.cc",
+ "frame_metrics_test_common.cc",
+ "frame_metrics_test_common.h",
+ "histograms_unittest.cc",
"latency_info_unittest.cc",
+ "stream_analyzer_unittest.cc",
+ "windowed_analyzer_unittest.cc",
]
deps = [
@@ -63,3 +77,21 @@ test("latency_unittests") {
]
}
}
+
+test("latency_perftests") {
+ sources = [
+ "frame_metrics_test_common.cc",
+ "frame_metrics_test_common.h",
+ "histograms_perftest.cc",
+ ]
+
+ deps = [
+ ":latency",
+ "//base",
+ "//base/test:test_support",
+ "//mojo/edk/test:run_all_unittests",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//testing/perf",
+ ]
+}
diff --git a/chromium/ui/latency/OWNERS b/chromium/ui/latency/OWNERS
index b29cc1a125a..691efe52575 100644
--- a/chromium/ui/latency/OWNERS
+++ b/chromium/ui/latency/OWNERS
@@ -1 +1,5 @@
+# latency info
tdresser@chromium.org
+
+# frame metrics
+brianderson@chromium.org
diff --git a/chromium/ui/latency/fixed_point.cc b/chromium/ui/latency/fixed_point.cc
new file mode 100644
index 00000000000..fafcf9ee85e
--- /dev/null
+++ b/chromium/ui/latency/fixed_point.cc
@@ -0,0 +1,61 @@
+// 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/latency/fixed_point.h"
+
+#include <cmath>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace ui {
+namespace frame_metrics {
+
+namespace {
+
+constexpr uint64_t k2Pow32{1ULL << 32};
+constexpr uint64_t k32LsbMask{0xFFFFFFFF};
+
+} // namespace
+
+Accumulator96b::Accumulator96b(uint32_t value_to_square, uint32_t weight) {
+ uint64_t square = static_cast<uint64_t>(value_to_square) * value_to_square;
+ uint64_t ms64b_temp = (square >> 32) * weight;
+ uint64_t ls32b_temp = (square & k32LsbMask) * weight;
+ ms64b = ms64b_temp + (ls32b_temp >> 32);
+ ls32b = ls32b_temp & k32LsbMask;
+}
+
+void Accumulator96b::Add(const Accumulator96b& rhs) {
+ uint64_t ls32b_temp = static_cast<uint64_t>(ls32b) + rhs.ls32b;
+ DCHECK_LT((ls32b_temp >> 32),
+ std::numeric_limits<decltype(ms64b)>::max() - rhs.ms64b)
+ << "Accumulator96b overflow.";
+ uint64_t ms64b_add = rhs.ms64b + (ls32b_temp >> 32);
+ DCHECK_LT(ms64b_add, std::numeric_limits<decltype(ms64b)>::max() - ms64b)
+ << "Accumulator96b overflow.";
+ ms64b += ms64b_add;
+ ls32b = ls32b_temp & k32LsbMask;
+}
+
+void Accumulator96b::Subtract(const Accumulator96b& rhs) {
+ uint64_t ls32b_temp = ls32b;
+ if (ls32b < rhs.ls32b) {
+ // Borrow from ms64b to ls32b.
+ ms64b--;
+ ls32b_temp |= k2Pow32;
+ }
+ DCHECK_GE(ms64b, rhs.ms64b) << "Accumulator96b underflow.";
+ DCHECK_GE(ls32b_temp, static_cast<uint64_t>(rhs.ls32b))
+ << "Accumulator96b underflow.";
+ ms64b -= rhs.ms64b;
+ ls32b = ls32b_temp - rhs.ls32b;
+}
+
+double Accumulator96b::ToDouble() const {
+ return (static_cast<double>(ms64b) * k2Pow32) + ls32b;
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/fixed_point.h b/chromium/ui/latency/fixed_point.h
new file mode 100644
index 00000000000..11b419116b3
--- /dev/null
+++ b/chromium/ui/latency/fixed_point.h
@@ -0,0 +1,71 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_FRAME_METRICS_FIXED_POINT_H_
+#define UI_FRAME_METRICS_FIXED_POINT_H_
+
+#include <cstdint>
+
+#include "base/macros.h"
+
+namespace ui {
+namespace frame_metrics {
+
+// Use fixed point math so we can manage our precision explicitly and avoid
+// accumulating error in our windowed accumulators.
+// The 64-bit accumulators reserve 32-bits for weights, and 32-bits for values.
+// The 32-bit values reserve 16 bits before and after the radix point.
+constexpr int kFixedPointShift = 16;
+constexpr int64_t kFixedPointMultiplier{1LL << kFixedPointShift};
+
+// kFixedPointRootMultiplier is used to shift the bits before taking the square
+// root and undoing that shift after squaring in the SMR calculation.
+constexpr int kFixedPointRootShift = 32;
+constexpr int64_t kFixedPointRootMultiplier{1LL << kFixedPointRootShift};
+constexpr int64_t kFixedPointRootMultiplierSqrt{1LL
+ << (kFixedPointRootShift / 2)};
+
+// We need a huge range to accumulate values for RMS calculations, which
+// need double the range internally compared to the range we are targeting
+// after taking the square root of the accumulation.
+// This efficiently emulates a 96-bit unsigned integer with weighted
+// accumulation operations.
+// 32-bits are reserved for weights and 64-bits for squared values.
+// Overflow or underflow indicates something is seriously wrong with the higher
+// level metrics logic, so this class will DCHECK if it anticipates overflow
+// or underflow:
+// * It doesn't need to support OVERFLOW since the frame metric classes will
+// always reset the entire accumulator before the accumulated weights
+// overflow. The accumulated weights correspond to a maximum of the number of
+// microseconds since the last reset, which for a 32-bit weight is about
+// 1 hour. We will gather and reset results much more often than every hour.
+// * It doesn't need to support UNDERFLOW since only the windowed metrics use
+// Subtract, and those only subtract values it has already added.
+class Accumulator96b {
+ public:
+ Accumulator96b() = default;
+ Accumulator96b(uint32_t value_to_square, uint32_t weight);
+
+ void Add(const Accumulator96b& rhs);
+ void Subtract(const Accumulator96b& rhs);
+ double ToDouble() const;
+
+ public:
+ uint64_t ms64b{0};
+ uint32_t ls32b{0};
+};
+
+// Convenience function overloads for AsDouble, to help with templated code.
+inline double AsDouble(const Accumulator96b& value) {
+ return value.ToDouble();
+}
+
+inline double AsDouble(double value) {
+ return value;
+}
+
+} // namespace frame_metrics
+} // namespace ui
+
+#endif // UI_FRAME_METRICS_FIXED_POINT_H_
diff --git a/chromium/ui/latency/fixed_point_unittest.cc b/chromium/ui/latency/fixed_point_unittest.cc
new file mode 100644
index 00000000000..02548fd03da
--- /dev/null
+++ b/chromium/ui/latency/fixed_point_unittest.cc
@@ -0,0 +1,149 @@
+// 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/latency/fixed_point.h"
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace frame_metrics {
+
+// Verify range of a fixed point value stored as a uint32_t has enough range
+// for our requirements.
+TEST(FrameMetricsFixedPointTest, kFixedPointMultiplier) {
+ uint32_t max_fixed = std::numeric_limits<uint32_t>::max();
+ double max_float = static_cast<double>(max_fixed) / kFixedPointMultiplier;
+
+ // The maximum time delta between two frames we'd like to support.
+ double frame_delta = 64 * base::TimeTicks::kMicrosecondsPerSecond;
+
+ // The minimum frame duration we'd like to support.
+ // 1kHz should give us plenty of headroom.
+ double frame_duration = base::TimeTicks::kMicrosecondsPerSecond / 1000;
+
+ // Verify the resulting slope is within the range.
+ double frame_slope = frame_delta / frame_duration;
+ EXPECT_LE(frame_slope, max_float);
+}
+
+// Some code will take the square root of a 32-bit value by shifting it left
+// 32-bits beforehand. Verify this is okay and more accurate than not shifting
+// at all.
+TEST(FrameMetricsFixedPointTest, kFixedPointRootMultiplier) {
+ uint64_t value = 0xFFFFFFFF;
+
+ // Calculate SMR with kFixedPointRootMultiplier.
+ // Truncate to 32 bits to verify multiplying by kFixedPointRootMultiplier
+ // will not result in overflow when stored as a 32 bit value.
+ uint32_t root1 = std::sqrt(value * kFixedPointRootMultiplier);
+ double value1 =
+ static_cast<uint64_t>(root1) * root1 / kFixedPointRootMultiplier;
+ double error1 = std::abs(value1 - value);
+
+ // Calculate SMR without kFixedPointRootMultiplier.
+ uint32_t root2 = std::sqrt(value);
+ double value2 = root2 * root2;
+ double error2 = std::abs(value2 - value);
+
+ // Verify using kFixedPointRootMultiplier is relatively more accurate.
+ EXPECT_LE(error1, error2);
+
+ // Verify using kFixedPointRootMultiplier is accurate in an absolute sense.
+ EXPECT_LE(error1, 1);
+}
+
+TEST(FrameMetricsFixedPointTest, kFixedPointRootMultiplierSqrt) {
+ EXPECT_EQ(kFixedPointRootMultiplierSqrt,
+ std::sqrt(kFixedPointRootMultiplier));
+}
+
+TEST(FrameMetricsFixedPointTest, kFixedPointRootShift) {
+ EXPECT_EQ(kFixedPointRootMultiplier, 1LL << kFixedPointRootShift);
+}
+
+// Verify Accumulator96b's squared weight constructor.
+TEST(FrameMetricsFixedPointTest, Accumulator96bConstructor) {
+ // A small value that fits in 32 bits.
+ uint64_t a = 13;
+ Accumulator96b a1(a, 2);
+ EXPECT_DOUBLE_EQ(a1.ToDouble(), a * a * 2);
+
+ // A "medium" value that fits in 64 bits.
+ uint64_t b = 0x10000001;
+ Accumulator96b a2(b, 2);
+ EXPECT_DOUBLE_EQ(a2.ToDouble(), b * b * 2);
+
+ // A large value that fits in 96 bits.
+ uint64_t c = 0x80000001;
+ Accumulator96b a3(c, c);
+ EXPECT_DOUBLE_EQ(a3.ToDouble(), std::pow(c, 3));
+
+ // The largest initial 96-bit value.
+ uint64_t d = 0xFFFFFFFF;
+ Accumulator96b a4(d, d);
+ EXPECT_DOUBLE_EQ(a4.ToDouble(), std::pow(d, 3));
+
+ // A mix of the two above.
+ double cf = c;
+ double df = d;
+ Accumulator96b a5(c, d);
+ EXPECT_DOUBLE_EQ(a5.ToDouble(), cf * cf * df);
+ Accumulator96b a6(d, c);
+ EXPECT_DOUBLE_EQ(a6.ToDouble(), df * df * cf);
+}
+
+// Verify Accumulator96b::Add and Subtract.
+TEST(FrameMetricsFixedPointTest, Accumulator96bAddSub) {
+ uint32_t v = 0xFFFFFFFF;
+
+ // A small value that fits in 32 bits and would carry into
+ // upper most 64 bits during accumulation.
+ Accumulator96b a1(1, v);
+ Accumulator96b accum1;
+ for (int i = 0; i <= 0xFF; i++) {
+ accum1.Add(a1);
+ EXPECT_DOUBLE_EQ(accum1.ToDouble(), static_cast<double>(v) * (i + 1));
+ }
+ for (int i = 0xFF; i >= 0; i--) {
+ accum1.Subtract(a1);
+ EXPECT_DOUBLE_EQ(accum1.ToDouble(), static_cast<double>(v) * i);
+ }
+
+ // A larger value that fits in 64 bits and would carry into
+ // upper most 32 bits during accumulation.
+ Accumulator96b a2(v, 1);
+ Accumulator96b accum2;
+ for (int i = 0; i <= 0xFF; i++) {
+ accum2.Add(a2);
+ EXPECT_DOUBLE_EQ(accum2.ToDouble(), static_cast<double>(v) * v * (i + 1));
+ }
+ for (int i = 0xFF; i >= 0; i--) {
+ accum2.Subtract(a2);
+ EXPECT_DOUBLE_EQ(accum2.ToDouble(), static_cast<double>(v) * v * i);
+ }
+}
+
+// Verify Accumulator96b precision is always 1.
+TEST(FrameMetricsFixedPointTest, Accumulator96bPrecision) {
+ uint32_t v = 0xFFFFFFFF;
+ Accumulator96b a1(1, 1); // 1. Smallest non-zero value possible.
+ Accumulator96b a2(v, v); // Largest initial value possible.
+ Accumulator96b a3(v, v); // Largest initial value possible, minus 1.
+ a3.Subtract(a1);
+
+ // Verify that conversion to a double loses precision from a3.
+ double a2f = a2.ToDouble();
+ double a3f = a3.ToDouble();
+ EXPECT_DOUBLE_EQ(a2f, a3f);
+ EXPECT_DOUBLE_EQ(0, a2f - a3f);
+
+ // Verify delta between a2 and a3 is 1 when computed internally.
+ Accumulator96b a4(a2);
+ a4.Subtract(a3);
+ EXPECT_DOUBLE_EQ(1, a4.ToDouble());
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/frame_metrics_test_common.cc b/chromium/ui/latency/frame_metrics_test_common.cc
new file mode 100644
index 00000000000..15125fca1eb
--- /dev/null
+++ b/chromium/ui/latency/frame_metrics_test_common.cc
@@ -0,0 +1,92 @@
+// 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/latency/frame_metrics_test_common.h"
+
+#include "base/logging.h"
+
+namespace ui {
+namespace frame_metrics {
+
+double TestStreamAnalyzerClient::TransformResult(double result) const {
+ return result * result_scale;
+}
+
+template <>
+void AddSamplesHelper(StreamAnalyzer* analyzer,
+ uint64_t value,
+ uint64_t weight,
+ size_t iterations) {
+ DCHECK_LE(value, std::numeric_limits<uint32_t>::max());
+ DCHECK_LE(weight, std::numeric_limits<uint32_t>::max());
+ for (size_t i = 0; i < iterations; i++) {
+ analyzer->AddSample(value, weight);
+ }
+}
+
+TestRatioBoundaries::TestRatioBoundaries() {
+ const uint32_t one = kFixedPointMultiplier;
+ const uint32_t half = one / 2;
+ // [0, 2^-16) => 1 bucket.
+ int i = 0;
+ boundaries[i++] = 0;
+ // [2^-16,1) pow of 2 strides => 16 buckets. (16x1)
+ for (int j = 0; j < 16; j++)
+ boundaries[i++] = 1ULL << j;
+ // [1,16) stride 1/2 => 30 buckets. (2 + 4 + 8 + 16)
+ for (int j = 0; j < 30; j++)
+ boundaries[i++] = one + (j * half);
+ // [16,32) stride 1 => 16 buckets.
+ for (int j = 0; j < 16; j++)
+ boundaries[i++] = (16 + j) * one;
+ // [32,64) stride 2 => 16 buckets.
+ for (int j = 0; j < 16; j++)
+ boundaries[i++] = (32 + 2 * j) * one;
+ // [64,128) stride 8 => 8 buckets.
+ for (int j = 0; j < 8; j++)
+ boundaries[i++] = (64 + 8 * j) * one;
+ // [128, 256) stride 16 => 8 buckets.
+ for (int j = 0; j < 8; j++)
+ boundaries[i++] = (128 + 16 * j) * one;
+ // [256, 512) stride 64 => 4 buckets.
+ for (int j = 0; j < 4; j++)
+ boundaries[i++] = (256 + 64 * j) * one;
+ // [512, 1024) stride 128 => 4 buckets.
+ for (int j = 0; j < 4; j++)
+ boundaries[i++] = (512 + 128 * j) * one;
+ // [1024, 2048) stride 512 => 2 buckets.
+ for (int j = 0; j < 2; j++)
+ boundaries[i++] = (1024 + 512 * j) * one;
+ // [2048, 4096) stride 1024 => 2 buckets.
+ for (int j = 0; j < 2; j++)
+ boundaries[i++] = (2048 + 1024 * j) * one;
+ // [4096, 2^16) pow of 2 strides => 4 buckets. (4x1)
+ for (int j = 0; j < 4; j++)
+ boundaries[i++] = (4096ULL << j) * one;
+ boundaries[i++] = 1ULL << 32;
+ DCHECK_EQ(112, i);
+}
+
+TestHistogram::TestHistogram() = default;
+TestHistogram::~TestHistogram() = default;
+
+void TestHistogram::AddSample(uint32_t value, uint32_t weight) {
+ added_samples_.push_back({value, weight});
+}
+
+PercentileResults TestHistogram::ComputePercentiles() const {
+ return results_;
+}
+
+std::vector<TestHistogram::ValueWeightPair>
+TestHistogram::GetAndResetAllAddedSamples() {
+ return std::move(added_samples_);
+}
+
+void TestHistogram::SetResults(PercentileResults results) {
+ results_ = results;
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/frame_metrics_test_common.h b/chromium/ui/latency/frame_metrics_test_common.h
new file mode 100644
index 00000000000..7dbe380fbd6
--- /dev/null
+++ b/chromium/ui/latency/frame_metrics_test_common.h
@@ -0,0 +1,174 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_LATENCY_FRAME_METRICS_TEST_COMMON_H_
+#define UI_LATENCY_FRAME_METRICS_TEST_COMMON_H_
+
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/histograms.h"
+#include "ui/latency/stream_analyzer.h"
+#include "ui/latency/windowed_analyzer.h"
+
+#include <array>
+
+// Some convenience macros for checking expected error.
+#define EXPECT_ABS_LT(a, b) EXPECT_LT(std::abs(a), std::abs(b))
+#define EXPECT_ABS_LE(a, b) EXPECT_LE(std::abs(a), std::abs(b))
+#define EXPECT_NEAR_SMR(expected, actual, weight) \
+ EXPECT_NEAR(expected, actual, MaxErrorSMR(expected, weight))
+#define EXPECT_NEAR_VARIANCE_OF_ROOT(expected, actual, mean, weight) \
+ EXPECT_NEAR(expected, actual, MaxErrorSMR(mean, weight));
+
+namespace ui {
+namespace frame_metrics {
+
+// A simple client to verify it is actually used.
+class TestStreamAnalyzerClient : public StreamAnalyzerClient {
+ public:
+ double TransformResult(double result) const override;
+ static constexpr double result_scale = 2.0;
+};
+
+using TestWindowedAnalyzerClient = TestStreamAnalyzerClient;
+
+// The WindowedAnalyzer expects the caller to give it some precomputed values,
+// even though they are redundant. Precompute them with a helper function to
+// remove boilerplate.
+// A specialized version of this for StreamAnalyzer that doesn't pre compute
+// the weighted values is defined in the implementation file.
+template <typename AnalyzerType>
+void AddSamplesHelper(AnalyzerType* analyzer,
+ uint64_t value,
+ uint64_t weight,
+ size_t iterations) {
+ DCHECK_LE(value, std::numeric_limits<uint32_t>::max());
+ DCHECK_LE(weight, std::numeric_limits<uint32_t>::max());
+ uint64_t weighted_value = weight * value;
+ uint64_t weighted_root = weight * std::sqrt(value << kFixedPointRootShift);
+ Accumulator96b weighted_square(value, weight);
+ for (size_t i = 0; i < iterations; i++) {
+ analyzer->AddSample(value, weight, weighted_value, weighted_root,
+ weighted_square);
+ }
+}
+
+// A specialization of the templatized AddSamplesHelper above for
+// the WindowedAnalyzer, which doesn't need to have it's weighted values
+// pre computed.
+template <>
+void AddSamplesHelper(StreamAnalyzer* analyzer,
+ uint64_t value,
+ uint64_t weight,
+ size_t iterations);
+
+// Moves the |shared_client|'s window forward in time by 1 microsecond and
+// adds all of the elements in |values| multipled by kFixedPointMultiplier.
+template <typename AnalyzerType>
+void AddPatternHelper(SharedWindowedAnalyzerClient* shared_client,
+ AnalyzerType* analyzer,
+ const std::vector<uint32_t>& values,
+ const uint32_t weight) {
+ for (auto i : values) {
+ shared_client->window_begin += base::TimeDelta::FromMicroseconds(1);
+ shared_client->window_end += base::TimeDelta::FromMicroseconds(1);
+ AddSamplesHelper(analyzer, i * kFixedPointMultiplier, weight, 1);
+ }
+}
+
+// Same as AddPatternHelper, but uses each value (+1) as its own weight.
+// The "Cubed" name comes from the fact that the squared_accumulator
+// for the RMS will effectively be a "cubed accumulator".
+template <typename AnalyzerType>
+void AddCubedPatternHelper(SharedWindowedAnalyzerClient* shared_client,
+ AnalyzerType* analyzer,
+ const std::vector<uint32_t>& values) {
+ for (auto i : values) {
+ shared_client->window_begin += base::TimeDelta::FromMicroseconds(1);
+ shared_client->window_end += base::TimeDelta::FromMicroseconds(1);
+ // weight is i+1 to avoid divide by zero.
+ AddSamplesHelper(analyzer, i, i + 1, 1);
+ }
+}
+
+// Mean and RMS can be exact for most values, however SMR loses a bit of
+// precision internally when accumulating the roots. Make sure the SMR
+// precision is at least within .5 (i.e. rounded to the nearest integer
+// properly), or 8 decimal places if that is less precise.
+// When used with kFixedPointMultiplier, this gives us a total precision of
+// between ~5 and ~13 decimal places.
+// The precision should be even better when the sample's |weight| > 1 since
+// the implementation should only do any rounding after scaling by weight.
+inline double MaxErrorSMR(double expected_value, uint64_t weight) {
+ return std::max(.5, 1e-8 * expected_value / weight);
+}
+
+// This class initializes the ratio boundaries on construction in a way that
+// is easier to follow than the procedural code in the RatioHistogram
+// implementation.
+class TestRatioBoundaries {
+ public:
+ TestRatioBoundaries();
+ uint64_t operator[](size_t i) const { return boundaries[i]; }
+ size_t size() const { return boundaries.size(); }
+
+ public:
+ // uint64_t since the last boundary needs 33 bits.
+ std::array<uint64_t, 112> boundaries;
+};
+
+// An explicit list of VSync boundaries to verify the procedurally generated
+// ones in the implementation.
+static constexpr std::array<uint32_t, 99> kTestVSyncBoundries = {
+ {// C0: [0,1) (1 bucket).
+ 0,
+ // C1: Powers of two from 1 to 2048 us @ 50% precision (12 buckets)
+ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
+ // C2: Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision (16 buckets)
+ 3906, 4032, 4167, 4310, 4464, 4630, 4808, 5000, 5208, 5435, 5682, 5952,
+ 6250, 6579, 6944, 7353,
+ // C3: Every 4 Hz from 128 Hz to 64 Hz @ 3-6% precision (16 buckets)
+ 7813, 8065, 8333, 8621, 8929, 9259, 9615, 10000, 10417, 10870, 11364,
+ 11905, 12500, 13158, 13889, 14706,
+ // C4: Every 2 Hz from 64 Hz to 32 Hz @ 3-6% precision (16 buckets)
+ 15625, 16129, 16667, 17241, 17857, 18519, 19231, 20000, 20833, 21739,
+ 22727, 23810, 25000, 26316, 27778, 29412,
+ // C5: Every 1 Hz from 32 Hz to 1 Hz @ 3-33% precision (31 buckets)
+ 31250, 32258, 33333, 34483, 35714, 37037, 38462, 40000, 41667, 43478,
+ 45455, 47619, 50000, 52632, 55556, 58824, 62500, 66667, 71429, 76923,
+ 83333, 90909, 100000, 111111, 125000, 142857, 166667, 200000, 250000,
+ 333333, 500000,
+ // C6: Powers of two from 1s to 32s @ 50% precision (6 buckets)
+ 1000000, 2000000, 4000000, 8000000, 16000000, 32000000,
+ // C7: Extra value to simplify estimate in Percentiles().
+ 64000000}};
+
+// A histogram that can be used for dependency injection in tests.
+class TestHistogram : public Histogram {
+ public:
+ struct ValueWeightPair {
+ uint32_t value;
+ uint32_t weight;
+ };
+
+ TestHistogram();
+ ~TestHistogram() override;
+
+ // Histogram interface.
+ void AddSample(uint32_t value, uint32_t weight) override;
+ PercentileResults ComputePercentiles() const override;
+ void Reset() override{};
+
+ // Test interface.
+ std::vector<ValueWeightPair> GetAndResetAllAddedSamples();
+ void SetResults(PercentileResults results);
+
+ private:
+ PercentileResults results_;
+ std::vector<ValueWeightPair> added_samples_;
+};
+
+} // namespace frame_metrics
+} // namespace ui
+
+#endif // UI_LATENCY_FRAME_METRICS_TEST_COMMON_H_
diff --git a/chromium/ui/latency/histograms.cc b/chromium/ui/latency/histograms.cc
new file mode 100644
index 00000000000..e7cd947278f
--- /dev/null
+++ b/chromium/ui/latency/histograms.cc
@@ -0,0 +1,385 @@
+// 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/latency/histograms.h"
+
+#include <cmath>
+#include <limits>
+
+#include "base/bits.h"
+#include "base/time/time.h"
+#include "ui/latency/fixed_point.h"
+
+namespace {
+
+// Calculates percentiles in a way that can be shared by different histograms.
+ui::PercentileResults PercentilesHelper(
+ ui::frame_metrics::BoundaryIterator* boundary_iterator,
+ const uint32_t* buckets_begin,
+ const uint32_t* buckets_end,
+ uint64_t total_samples) {
+ ui::PercentileResults result;
+ uint64_t boundary_left = 0;
+ uint64_t boundary_right = boundary_iterator->Next();
+
+ double thresholds[ui::PercentileResults::kCount];
+ for (size_t i = 0; i < ui::PercentileResults::kCount; i++) {
+ thresholds[i] = ui::PercentileResults::kPercentiles[i] * total_samples;
+ }
+
+ uint64_t accumulator = 0;
+ size_t result_index = 0;
+ for (const uint32_t* bucket = buckets_begin; bucket < buckets_end; bucket++) {
+ accumulator += *bucket;
+ // Multiple percentiles might be calculated from the same bucket,
+ // so we use a while loop here.
+ while (accumulator > thresholds[result_index]) {
+ const double overage = accumulator - thresholds[result_index];
+ double b0_fraction = overage / (*bucket);
+ double b1_fraction = 1.0 - b0_fraction;
+
+ // Use a linear interpolation between two buckets.
+ // This assumes the samples are evenly distributed within a bucket.
+ // TODO(brianderson): Consider neighboring bucket sizes and fit to a
+ // curve. http://crbug.com/821879
+ const double estimate =
+ b0_fraction * boundary_left + b1_fraction * boundary_right;
+ result.values[result_index] = estimate;
+ result_index++;
+ if (result_index >= ui::PercentileResults::kCount)
+ return result;
+ }
+
+ boundary_left = boundary_right;
+ boundary_right = boundary_iterator->Next();
+ }
+
+ NOTREACHED();
+ return result;
+}
+
+} // namespace
+
+namespace ui {
+
+constexpr double PercentileResults::kPercentiles[];
+constexpr size_t PercentileResults::kCount;
+
+namespace frame_metrics {
+
+constexpr size_t RatioHistogram::kBucketCount;
+constexpr size_t VSyncHistogram::kBucketCount;
+
+// Ratio Histogram.
+// The distribution of each category of buckets in this historam is
+// exponential, however each category is divided into N linear buckets
+// depending on how much precision we want for that category. How much
+// precision a category gets depends on how often we expect that bucket to be
+// used and how important those buckets are.
+//
+// Most of the precision is allocated for values just > 1 since most ratios,
+// when not ~0 will be > 1. And since ratios are likely to be near whole
+// numbers (some multiple of the vsync), we only give it a precision of 1/2.
+// You can think about the stride of each category as the number of vsyncs of
+// precision that category will have.
+//
+// There will be aliasing, but because of the vsync aligned linear division
+// of each category, we won't get a bucket that represents fewer vsyncs than
+// its fprevious bucket.
+//
+// This is in contrast to the default exponential distribution of UMA
+// buckets, which result in a constant precision for each bucket and would
+// allocate lots of very small buckets near 0 where we don't need the
+// precision.
+
+namespace {
+
+constexpr size_t kBucketHalfStrideFirstBucketIndex = 17;
+
+// Within the range [16, 4096), there are 9 categories of buckets that each
+// start with a power of 2. Within a category, successive buckets have a fixed
+// stride. Across categories, the strides increase exponentionally, encoded
+// as powers of 2 in |stride_shift|, which increases linearly.
+struct RatioBucketCategory {
+ uint8_t first_bucket_index;
+ uint8_t stride_shift;
+};
+using RatioCategoryHelper = std::array<RatioBucketCategory, 9>;
+constexpr RatioCategoryHelper kCategories16to4096 = {
+ // first_bucket_index of each row below is the previous one + number of
+ // buckets. Each entry is {first_bucket_index, stride_shift}.
+ {{47, 0}, // [16, 32) stride 1 => 16 buckets.
+ {63, 1}, // [32, 64) stride 2 => 16 buckets.
+ {79, 3}, // [64, 128) stride 8 => 8 buckets.
+ {87, 4}, // [128, 256) stride 16 => 8 buckets.
+ {95, 6}, // [256, 512) stride 64 => 4 buckets
+ {99, 7}, // [512, 1024) stride 128 => 4 buckets.
+ {103, 9}, // [1024, 2048) stride 512 => 2 buckets.
+ {105, 10}, // [2048, 4096) stride 1024 => 2 buckets.
+ {107, 12}}}; // [4096, 8192) stride 4096 => 1 bucket.
+
+// The delegate RatioBoundary::Percentiles will pass to PercentilesHelper.
+struct RatioBoundaryIterator : public BoundaryIterator {
+ ~RatioBoundaryIterator() override = default;
+
+ size_t bucket = 0;
+ uint64_t boundary = 0;
+ RatioCategoryHelper::const_iterator b16to4096 = kCategories16to4096.begin();
+ uint64_t next_boundary_to_change_category =
+ 32 * frame_metrics::kFixedPointMultiplier;
+
+ uint64_t Next() override {
+ if (bucket == 0) {
+ // The first bucket is [0, 1).
+ boundary = 1;
+ } else if (bucket < kBucketHalfStrideFirstBucketIndex ||
+ bucket >= kCategories16to4096.back().first_bucket_index) {
+ // The start and end buckets increase in size by powers of 2.
+ boundary *= 2;
+ } else if (bucket < kCategories16to4096.front().first_bucket_index) {
+ // The 30 buckets before 47 have a stride of .5 and represent the
+ // range [1, 16).
+ boundary += (frame_metrics::kFixedPointMultiplier / 2);
+ } else {
+ // The rest of the buckets are defined by kCategories16to4096.
+ DCHECK(b16to4096 < kCategories16to4096.end());
+ boundary +=
+ (frame_metrics::kFixedPointMultiplier << b16to4096->stride_shift);
+ // The category changes for every power of 2.
+ if (boundary >= next_boundary_to_change_category) {
+ next_boundary_to_change_category *= 2;
+ b16to4096++;
+ }
+ }
+
+ bucket++;
+ return boundary;
+ }
+};
+
+} // namespace
+
+std::unique_ptr<BoundaryIterator> CreateRatioIteratorForTesting() {
+ return std::make_unique<RatioBoundaryIterator>();
+}
+
+RatioHistogram::RatioHistogram() = default;
+RatioHistogram::~RatioHistogram() = default;
+
+void RatioHistogram::AddSample(uint32_t ratio, uint32_t weight) {
+ size_t bucket = 0;
+
+ // Precomputed thresholds for the log base 2 of the ratio that help
+ // determine which category of buckets the sample should go in.
+ constexpr int kLog2HalfStrideStart = kFixedPointShift;
+ constexpr int kLog2Cats16to4096Start = kFixedPointShift + 4; // 2^4 = 16.
+ constexpr int kLog2_4096Pow2Start = kFixedPointShift + 12; // 2^12 = 4096.
+
+ if (ratio == 0) {
+ bucket = 0;
+ } else {
+ int log2 = base::bits::Log2Floor(ratio);
+ DCHECK_GE(log2, 0);
+ if (log2 < kLog2HalfStrideStart) {
+ // [2^-16, 1) pow of 2 strides => 16 buckets. (16x1)
+ bucket = 1 + log2;
+ } else if (log2 < kLog2Cats16to4096Start) {
+ // [1, 16) stride 1/2 => 30 buckets. (2 + 4 + 8 + 16)
+ const int first_bucket_index = kBucketHalfStrideFirstBucketIndex;
+ const int category_start = kFixedPointMultiplier;
+ const int total_shift = kFixedPointShift - 1; // -1 multiplies by 2.
+ const int category_offset = (ratio - category_start) >> total_shift;
+ bucket = first_bucket_index + category_offset;
+ } else if (log2 < kLog2_4096Pow2Start) {
+ // [16, 32) stride 1 => 16 buckets.
+ // [32, 64) stride 2 => 16 buckets.
+ // [64, 128) stride 8 => 8 buckets.
+ // [128, 256) stride 16 => 8 buckets.
+ // [256, 512) stride 64 => 4 buckets.
+ // [512, 1024) stride 128 => 4 buckets.
+ // [1024, 2048) stride 512 => 2 buckets.
+ // [2048, 4096) stride 1024 => 2 buckets.
+ const int category = log2 - kLog2Cats16to4096Start;
+ const int category_start = 1 << log2;
+ const int total_shift =
+ (kFixedPointShift + kCategories16to4096[category].stride_shift);
+ const int category_offset = (ratio - category_start) >> total_shift;
+ bucket =
+ kCategories16to4096[category].first_bucket_index + category_offset;
+ } else {
+ // [4096, 2^16) pow of 2 strides => 4 buckets. (4x1)
+ const int category_offset = log2 - kLog2_4096Pow2Start;
+ bucket = kCategories16to4096.back().first_bucket_index + category_offset;
+ }
+ }
+ DCHECK_LT(bucket, kBucketCount);
+
+ // Verify overflow isn't an issue.
+ DCHECK_LT(weight, std::numeric_limits<BucketArray::value_type>::max() -
+ buckets_[bucket]);
+ DCHECK_LT(weight, std::numeric_limits<decltype(total_samples_)>::max() -
+ total_samples_);
+
+ buckets_[bucket] += weight;
+ total_samples_ += weight;
+}
+
+PercentileResults RatioHistogram::ComputePercentiles() const {
+ RatioBoundaryIterator i;
+ return PercentilesHelper(&i, buckets_.data(),
+ buckets_.data() + buckets_.size(), total_samples_);
+}
+
+void RatioHistogram::Reset() {
+ total_samples_ = 0;
+ buckets_.fill(0);
+}
+
+// VSyncHistogram.
+namespace {
+
+// The number of buckets in bucket categories 1 through 6.
+constexpr std::array<uint8_t, 6> kVSyncBucketCounts = {{12, 16, 16, 16, 31, 6}};
+
+// Some constants used to convert values to bucket categories.
+constexpr size_t kVSync1stBucketC0 = 0;
+constexpr size_t kVSync1stBucketC1 = kVSync1stBucketC0 + 1;
+constexpr size_t kVSync1stBucketC2 = kVSync1stBucketC1 + kVSyncBucketCounts[0];
+constexpr size_t kVSync1stBucketC3 = kVSync1stBucketC2 + kVSyncBucketCounts[1];
+constexpr size_t kVSync1stBucketC4 = kVSync1stBucketC3 + kVSyncBucketCounts[2];
+constexpr size_t kVSync1stBucketC5 = kVSync1stBucketC4 + kVSyncBucketCounts[3];
+constexpr size_t kVSync1stBucketC6 = kVSync1stBucketC5 + kVSyncBucketCounts[4];
+constexpr size_t kVSyncBucketCountC6 = kVSyncBucketCounts[5];
+
+// This iterates through the microsecond VSync boundaries.
+struct VSyncBoundaryIterator : public BoundaryIterator {
+ ~VSyncBoundaryIterator() override = default;
+
+ uint8_t category_ = 0;
+ uint8_t sub_bucket_ = 0;
+
+ uint64_t Next() override {
+ uint32_t boundary = 0;
+ switch (category_) {
+ case 0: // Powers of two from 1 to 2048 us @ 50% precision
+ boundary = 1 << sub_bucket_;
+ break;
+ case 1: // Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision
+ case 2: // Every 4 Hz from 128 Hz to 64 Hz @ 3-6% precision
+ case 3: // Every 2 Hz from 64 Hz to 32 Hz @ 3-6% precision
+ case 4: { // Every 1 Hz from 32 Hz to 1 Hz @ 3-33% precision
+ int hz_start = 256 >> (category_ - 1);
+ int hz_stride = 8 >> (category_ - 1);
+ int hz = hz_start - hz_stride * sub_bucket_;
+ boundary = (base::TimeTicks::kMicrosecondsPerSecond + (hz / 2)) / hz;
+ break;
+ }
+ case 5: // Powers of two from 1s to 32s @ 50% precision
+ boundary =
+ static_cast<uint32_t>(base::TimeTicks::kMicrosecondsPerSecond) *
+ (1 << sub_bucket_);
+ break;
+ case 6: // The last boundary of 64s.
+ // Advancing would result in out-of-bounds access of
+ // kVSyncBucketCounts, so just return.
+ return 64 * base::TimeTicks::kMicrosecondsPerSecond;
+ default:
+ NOTREACHED();
+ }
+
+ if (++sub_bucket_ >= kVSyncBucketCounts[category_]) {
+ category_++;
+ sub_bucket_ = 0;
+ }
+
+ return boundary;
+ }
+};
+
+} // namespace
+
+std::unique_ptr<BoundaryIterator> CreateVSyncIteratorForTesting() {
+ return std::make_unique<VSyncBoundaryIterator>();
+}
+
+VSyncHistogram::VSyncHistogram() = default;
+VSyncHistogram::~VSyncHistogram() = default;
+
+// Optimized to minimize the number of memory accesses.
+void VSyncHistogram::AddSample(uint32_t microseconds, uint32_t weight) {
+ size_t bucket = 0;
+
+ static constexpr int k256HzPeriodInMicroseconds =
+ base::TimeTicks::kMicrosecondsPerSecond / 256;
+
+ if (microseconds == 0) {
+ // bucket = 0;
+ } else if (microseconds < k256HzPeriodInMicroseconds) {
+ // Powers of two from 1 to 2048 us @ 50% precision
+ bucket = kVSync1stBucketC1 + base::bits::Log2Floor(microseconds);
+ } else if (microseconds < base::TimeTicks::kMicrosecondsPerSecond) {
+ // [256Hz, 1Hz)
+ int hz = base::TimeTicks::kMicrosecondsPerSecond / (microseconds + 0.5);
+ DCHECK_LT(hz, 256);
+ switch (hz / 32) {
+ // Every 1 Hz from 32 Hz to 1 Hz @ 3-33% precision
+ case 0:
+ bucket = kVSync1stBucketC6 - hz;
+ break;
+ // Every 2 Hz from 64 Hz to 32 Hz @ 3-6% precision
+ case 1:
+ bucket = kVSync1stBucketC5 - ((hz - 30) / 2);
+ break;
+ // Every 4 Hz from 128 Hz to 64 Hz @ 3-6% precision
+ case 2:
+ case 3:
+ bucket = kVSync1stBucketC4 - ((hz - 60) / 4);
+ break;
+ // Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ bucket = kVSync1stBucketC3 - ((hz - 120) / 8);
+ break;
+ default:
+ NOTREACHED();
+ return;
+ }
+ } else {
+ // Powers of two from 1s to 32s @ 50% precision
+ int seconds_log2 = base::bits::Log2Floor(
+ microseconds / base::TimeTicks::kMicrosecondsPerSecond);
+ DCHECK_GE(seconds_log2, 0);
+ size_t offset = std::min<size_t>(kVSyncBucketCountC6 - 1, seconds_log2);
+ bucket = kVSync1stBucketC6 + offset;
+ }
+
+ DCHECK_GE(bucket, 0u);
+ DCHECK_LT(bucket, kVSync1stBucketC6 + kVSyncBucketCountC6);
+ DCHECK_LT(bucket, kBucketCount);
+
+ // Verify overflow isn't an issue.
+ DCHECK_LT(weight, std::numeric_limits<BucketArray::value_type>::max() -
+ buckets_[bucket]);
+ DCHECK_LT(weight, std::numeric_limits<decltype(total_samples_)>::max() -
+ total_samples_);
+
+ buckets_[bucket] += weight;
+ total_samples_ += weight;
+}
+
+PercentileResults VSyncHistogram::ComputePercentiles() const {
+ VSyncBoundaryIterator i;
+ return PercentilesHelper(&i, buckets_.data(),
+ buckets_.data() + buckets_.size(), total_samples_);
+}
+
+void VSyncHistogram::Reset() {
+ total_samples_ = 0;
+ buckets_.fill(0);
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/histograms.h b/chromium/ui/latency/histograms.h
new file mode 100644
index 00000000000..bbe4ddb76a8
--- /dev/null
+++ b/chromium/ui/latency/histograms.h
@@ -0,0 +1,103 @@
+// 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_LATENCY_HISTOGRAMS_H_
+#define UI_LATENCY_HISTOGRAMS_H_
+
+#include <array>
+#include <memory>
+
+#include "base/macros.h"
+
+namespace ui {
+
+// Used to communicate percentile results to clients.
+struct PercentileResults {
+ static constexpr double kPercentiles[] = {.50, .99};
+ static constexpr size_t kCount = arraysize(kPercentiles);
+
+ double values[kCount]{};
+};
+
+namespace frame_metrics {
+
+// This is an interface different metrics will use to inject their ideal
+// histogram implementations into the StreamAnalyzer.
+class Histogram {
+ public:
+ Histogram() = default;
+ virtual ~Histogram() = default;
+
+ // Increases the bucket that contains |value| by |weight|.
+ virtual void AddSample(uint32_t value, uint32_t weight) = 0;
+
+ // Computes and returns the approximate percentiles based on the
+ // histogram distribution.
+ virtual PercentileResults ComputePercentiles() const = 0;
+
+ // Resets all buckets in the histogram to 0.
+ // Higher level logic may periodically reset the the counts after it
+ // gathers the percentiles in order to avoid overflow.
+ virtual void Reset() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+// Ratio histogram, with a range of [0, 2^32) and most of it's precision
+// just above kFixedPointMultiplier (i.e. a fixed point of 1).
+class RatioHistogram : public Histogram {
+ public:
+ RatioHistogram();
+ ~RatioHistogram() override;
+ void AddSample(uint32_t ratio, uint32_t weight) override;
+ PercentileResults ComputePercentiles() const override;
+ void Reset() override;
+
+ private:
+ static constexpr size_t kBucketCount = 111;
+
+ uint64_t total_samples_ = 0;
+ using BucketArray = std::array<uint32_t, kBucketCount>;
+ BucketArray buckets_{};
+
+ DISALLOW_COPY_AND_ASSIGN(RatioHistogram);
+};
+
+// A histogram of 98 buckets from 0 to 64 seconds with extra precision
+// around common vsync boundaries.
+class VSyncHistogram : public Histogram {
+ public:
+ VSyncHistogram();
+ ~VSyncHistogram() override;
+ void AddSample(uint32_t microseconds, uint32_t weight) override;
+ PercentileResults ComputePercentiles() const override;
+ void Reset() override;
+
+ private:
+ static constexpr size_t kBucketCount = 98;
+
+ uint64_t total_samples_ = 0;
+ using BucketArray = std::array<uint32_t, kBucketCount>;
+ BucketArray buckets_{};
+
+ DISALLOW_COPY_AND_ASSIGN(VSyncHistogram);
+};
+
+// An interface that allows PercentileHelper to iterate through the
+// bucket boundaries of the delegating histogram.
+// This is an implemenation detail, but is exposed here for testing purposes.
+struct BoundaryIterator {
+ virtual ~BoundaryIterator() = default;
+ virtual uint64_t Next() = 0;
+};
+
+// These expose the internal iterators, so they can be verified in tests.
+std::unique_ptr<BoundaryIterator> CreateRatioIteratorForTesting();
+std::unique_ptr<BoundaryIterator> CreateVSyncIteratorForTesting();
+
+} // namespace frame_metrics
+} // namespace ui
+
+#endif // UI_LATENCY_HISTOGRAMS_H_
diff --git a/chromium/ui/latency/histograms_perftest.cc b/chromium/ui/latency/histograms_perftest.cc
new file mode 100644
index 00000000000..ab7480fc3fc
--- /dev/null
+++ b/chromium/ui/latency/histograms_perftest.cc
@@ -0,0 +1,257 @@
+// 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/latency/histograms.h"
+
+#include <algorithm>
+
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/sample_vector.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/frame_metrics_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+
+constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(2);
+
+// A version of RatioHistogram based on the default implementations
+// of base::BucketRanges and base::SampleVector.
+class RatioHistogramBaseline : public Histogram {
+ public:
+ RatioHistogramBaseline()
+ : ratio_boundaries_(),
+ bucket_ranges_(ratio_boundaries_.size()),
+ sample_vector_(&bucket_ranges_) {
+ size_t i = 0;
+ for (const auto& b : ratio_boundaries_.boundaries) {
+ bucket_ranges_.set_range(i++, std::min<uint64_t>(b, INT_MAX));
+ }
+ }
+
+ ~RatioHistogramBaseline() override = default;
+
+ void AddSample(uint32_t microseconds, uint32_t weight) override {
+ sample_vector_.Accumulate(microseconds, weight);
+ }
+
+ PercentileResults ComputePercentiles() const override {
+ return PercentileResults();
+ }
+ void Reset() override {}
+
+ private:
+ TestRatioBoundaries ratio_boundaries_;
+ base::BucketRanges bucket_ranges_;
+ base::SampleVector sample_vector_;
+
+ DISALLOW_COPY_AND_ASSIGN(RatioHistogramBaseline);
+};
+
+TEST(FrameMetricsHistogramsPerfTest, RatioEntireRange) {
+ const int kStride = 0x1000;
+
+ RatioHistogramBaseline vh_base;
+ RatioHistogram vh_impl;
+
+ base::TimeDelta impl_time;
+ base::TimeDelta base_time;
+
+ base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+ while (base::TimeTicks::Now() < finish_time) {
+ // Impl then Base
+ for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+ int value = (i * 37) & 0x3FFFFFFF;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ impl_time += t1 - t0 - (t3 - t2);
+ base_time += t2 - t1 - (t3 - t2);
+ }
+
+ // Base then Impl
+ for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+ int value = (i * 37) & 0x3FFFFFFF;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ base_time += t1 - t0 - (t3 - t2);
+ impl_time += t2 - t1 - (t3 - t2);
+ }
+ }
+
+ double X = base_time.InSecondsF() / impl_time.InSecondsF();
+ perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+TEST(FrameMetricsHistogramsPerfTest, RatioCommonRange) {
+ const int kStride = 0x100;
+
+ RatioHistogramBaseline vh_base;
+ RatioHistogram vh_impl;
+
+ base::TimeDelta impl_time;
+ base::TimeDelta base_time;
+
+ base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+ while (base::TimeTicks::Now() < finish_time) {
+ // Impl then Base
+ for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
+ int value = i;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ impl_time += t1 - t0 - (t3 - t2);
+ base_time += t2 - t1 - (t3 - t2);
+ }
+
+ // Base then Impl
+ for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
+ int value = i;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ base_time += t1 - t0 - (t3 - t2);
+ impl_time += t2 - t1 - (t3 - t2);
+ }
+ }
+
+ double X = base_time.InSecondsF() / impl_time.InSecondsF();
+ perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+// A version of VSyncHistogram based on the default implementations
+// of base::BucketRanges and base::SampleVector.
+class VSyncHistogramBaseline : public Histogram {
+ public:
+ VSyncHistogramBaseline()
+ : bucket_ranges_(kTestVSyncBoundries.size() + 1),
+ sample_vector_(&bucket_ranges_) {
+ size_t i = 0;
+ for (const auto& b : kTestVSyncBoundries) {
+ bucket_ranges_.set_range(i++, b);
+ }
+ // BucketRanges needs the last element set to INT_MAX.
+ bucket_ranges_.set_range(i++, INT_MAX);
+ }
+
+ ~VSyncHistogramBaseline() override = default;
+
+ void AddSample(uint32_t microseconds, uint32_t weight) override {
+ sample_vector_.Accumulate(microseconds, weight);
+ }
+
+ PercentileResults ComputePercentiles() const override {
+ return PercentileResults();
+ }
+ void Reset() override {}
+
+ private:
+ base::BucketRanges bucket_ranges_;
+ base::SampleVector sample_vector_;
+
+ DISALLOW_COPY_AND_ASSIGN(VSyncHistogramBaseline);
+};
+
+TEST(FrameMetricsHistogramsPerfTest, VSyncEntireRange) {
+ const int kStride = 0x1000;
+
+ VSyncHistogramBaseline vh_base;
+ VSyncHistogram vh_impl;
+
+ base::TimeDelta impl_time;
+ base::TimeDelta base_time;
+
+ base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+ while (base::TimeTicks::Now() < finish_time) {
+ // Impl then Base
+ for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+ int value = (i * 37) % 64000000;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ impl_time += t1 - t0 - (t3 - t2);
+ base_time += t2 - t1 - (t3 - t2);
+ }
+
+ // Base then Impl
+ for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+ int value = (i * 37) % 64000000;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ base_time += t1 - t0 - (t3 - t2);
+ impl_time += t2 - t1 - (t3 - t2);
+ }
+ }
+
+ double X = base_time.InSecondsF() / impl_time.InSecondsF();
+ perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+TEST(FrameMetricsHistogramsPerfTest, VSyncCommonRange) {
+ const int kStride = 0x100;
+
+ VSyncHistogramBaseline vh_base;
+ VSyncHistogram vh_impl;
+
+ base::TimeDelta impl_time;
+ base::TimeDelta base_time;
+
+ base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+ while (base::TimeTicks::Now() < finish_time) {
+ // Impl then Base
+ for (int i = 0; i < 100000; i += kStride) {
+ int value = i;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ impl_time += t1 - t0 - (t3 - t2);
+ base_time += t2 - t1 - (t3 - t2);
+ }
+
+ // Base then Impl
+ for (int i = 0; i < 100000; i += kStride) {
+ int value = i;
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ vh_base.AddSample(value, 1);
+ base::TimeTicks t1 = base::TimeTicks::Now();
+ vh_impl.AddSample(value, 1);
+ base::TimeTicks t2 = base::TimeTicks::Now();
+ base::TimeTicks t3 = base::TimeTicks::Now();
+ base_time += t1 - t0 - (t3 - t2);
+ impl_time += t2 - t1 - (t3 - t2);
+ }
+ }
+
+ double X = base_time.InSecondsF() / impl_time.InSecondsF();
+ perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/histograms_unittest.cc b/chromium/ui/latency/histograms_unittest.cc
new file mode 100644
index 00000000000..4278f868733
--- /dev/null
+++ b/chromium/ui/latency/histograms_unittest.cc
@@ -0,0 +1,151 @@
+// 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/latency/histograms.h"
+
+#include <algorithm>
+
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/sample_vector.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/frame_metrics_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+
+// Verifies the ratio boundaries generated internally match the reference
+// boundaries.
+TEST(FrameMetricsHistogramsTest, RatioBoundariesDirect) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ std::unique_ptr<BoundaryIterator> ratio_impl =
+ CreateRatioIteratorForTesting();
+ for (uint32_t boundary : kTestRatioBoundaries.boundaries) {
+ if (boundary == 0)
+ continue;
+ EXPECT_EQ(boundary, ratio_impl->Next());
+ }
+}
+
+// Verifies the VSync boundaries generated internally match the reference
+// boundaries.
+TEST(FrameMetricsHistogramsTest, VSyncBoundariesDirect) {
+ std::unique_ptr<BoundaryIterator> vsync_impl =
+ CreateVSyncIteratorForTesting();
+ for (uint32_t boundary : kTestVSyncBoundries) {
+ if (boundary == 0)
+ continue;
+ EXPECT_EQ(boundary, vsync_impl->Next());
+ }
+}
+
+template <typename ReferenceBoundaryT>
+void BoundaryTestCommon(const ReferenceBoundaryT& reference_boundaries,
+ std::unique_ptr<Histogram> histogram) {
+ PercentileResults percentiles;
+
+ for (size_t i = 0; i < reference_boundaries.size() - 1; i++) {
+ uint64_t bucket_start = reference_boundaries[i];
+ uint64_t bucket_end = reference_boundaries[i + 1];
+
+ // Verify values within the current bucket don't affect percentile.
+ // This also checks the first value in the bucket.
+ uint32_t stride = std::max<uint32_t>(1u, (bucket_end - bucket_start) / 8);
+ for (uint64_t value = bucket_start; value < bucket_end; value += stride) {
+ histogram->AddSample(value, 1);
+ percentiles = histogram->ComputePercentiles();
+ histogram->Reset();
+ EXPECT_LE(bucket_start, percentiles.values[0]);
+ EXPECT_GT(bucket_end, percentiles.values[0]);
+ }
+
+ // Verify the value just before the next bucket doesn't affect percentile.
+ histogram->AddSample(bucket_end - 1, 1);
+ percentiles = histogram->ComputePercentiles();
+ histogram->Reset();
+ EXPECT_LE(bucket_start, percentiles.values[0]);
+ EXPECT_GT(bucket_end, percentiles.values[0]);
+ }
+}
+
+TEST(FrameMetricsHistogramsTest, RatioBoundaries) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ BoundaryTestCommon(kTestRatioBoundaries, std::make_unique<RatioHistogram>());
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncBoundaries) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ BoundaryTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>());
+}
+
+template <typename ReferenceBoundaryT>
+void PercentilesTestCommon(const ReferenceBoundaryT& reference_boundaries,
+ std::unique_ptr<Histogram> histogram,
+ int percentile_index) {
+ double percentile = PercentileResults::kPercentiles[percentile_index];
+ PercentileResults percentiles;
+ for (size_t i = 0; i < reference_boundaries.size() - 1; i++) {
+ uint64_t bucket_start = reference_boundaries[i];
+ uint64_t bucket_end = reference_boundaries[i + 1];
+
+ // Add samples to current bucket.
+ // Where the samples are added in the current bucket should not affect the
+ // result.
+ uint32_t stride = std::max<uint32_t>(1u, (bucket_end - bucket_start) / 100);
+ int samples_added_inside = 0;
+ for (uint64_t value = bucket_start; value < bucket_end; value += stride) {
+ histogram->AddSample(value, 10);
+ samples_added_inside += 10;
+ }
+
+ // Add samples to left and right of current bucket.
+ // Don't worry about doing this for the left most and right most buckets.
+ int samples_added_left = 0;
+ int samples_added_outside = 0;
+ if (i != 0 && i < reference_boundaries.size() - 2) {
+ samples_added_outside = 10000;
+ samples_added_left = samples_added_outside * percentile;
+ histogram->AddSample(bucket_start / 3, samples_added_left);
+ histogram->AddSample(bucket_start * 3,
+ samples_added_outside - samples_added_left);
+ }
+
+ percentiles = histogram->ComputePercentiles();
+ histogram->Reset();
+
+ double index = (samples_added_inside + samples_added_outside) * percentile -
+ samples_added_left;
+ double w = index / samples_added_inside;
+ double expected_value = bucket_end * w + bucket_start * (1.0 - w);
+ EXPECT_DOUBLE_EQ(expected_value, percentiles.values[percentile_index]);
+ }
+}
+
+TEST(FrameMetricsHistogramsTest, RatioPercentiles50th) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ PercentilesTestCommon(kTestRatioBoundaries,
+ std::make_unique<RatioHistogram>(), 0);
+}
+
+TEST(FrameMetricsHistogramsTest, RatioPercentiles99th) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ PercentilesTestCommon(kTestRatioBoundaries,
+ std::make_unique<RatioHistogram>(), 1);
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncPercentiles50th) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ PercentilesTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>(),
+ 0);
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncPercentiles99th) {
+ const TestRatioBoundaries kTestRatioBoundaries;
+ PercentilesTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>(),
+ 1);
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/mojo/BUILD.gn b/chromium/ui/latency/mojo/BUILD.gn
index 0840e693bd2..61d39750b7e 100644
--- a/chromium/ui/latency/mojo/BUILD.gn
+++ b/chromium/ui/latency/mojo/BUILD.gn
@@ -11,6 +11,7 @@ mojom("interfaces") {
public_deps = [
"//mojo/common:common_custom_types",
+ "//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
]
}
diff --git a/chromium/ui/latency/mojo/latency_info.mojom b/chromium/ui/latency/mojo/latency_info.mojom
index 9ebb386eb18..1b0e5e858cb 100644
--- a/chromium/ui/latency/mojo/latency_info.mojom
+++ b/chromium/ui/latency/mojo/latency_info.mojom
@@ -4,7 +4,7 @@
module ui.mojom;
-import "mojo/common/time.mojom";
+import "mojo/public/mojom/base/time.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
enum LatencyComponentType {
@@ -104,13 +104,13 @@ struct LatencyComponent {
// component.
int64 sequence_number;
// Average time of events that happened in this component.
- mojo.common.mojom.TimeTicks event_time;
+ mojo_base.mojom.TimeTicks event_time;
// Count of events that happened in this component
uint32 event_count;
// Time of the oldest event that happened in this component.
- mojo.common.mojom.TimeTicks first_event_time;
+ mojo_base.mojom.TimeTicks first_event_time;
// Time of the most recent event that happened in this component.
- mojo.common.mojom.TimeTicks last_event_time;
+ mojo_base.mojom.TimeTicks last_event_time;
};
struct LatencyComponentPair {
@@ -128,5 +128,5 @@ struct LatencyInfo {
bool began;
bool terminated;
SourceEventType source_event_type;
- mojo.common.mojom.TimeDelta expected_queueing_time_on_dispatch;
+ mojo_base.mojom.TimeDelta expected_queueing_time_on_dispatch;
};
diff --git a/chromium/ui/latency/mojo/latency_info_struct_traits.cc b/chromium/ui/latency/mojo/latency_info_struct_traits.cc
index 4f4d2316157..2e44de61973 100644
--- a/chromium/ui/latency/mojo/latency_info_struct_traits.cc
+++ b/chromium/ui/latency/mojo/latency_info_struct_traits.cc
@@ -4,7 +4,7 @@
#include "ui/latency/mojo/latency_info_struct_traits.h"
-#include "mojo/common/time_struct_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
namespace mojo {
diff --git a/chromium/ui/latency/mojo/latency_info_struct_traits.h b/chromium/ui/latency/mojo/latency_info_struct_traits.h
index 53e465ab55f..4fc347e777a 100644
--- a/chromium/ui/latency/mojo/latency_info_struct_traits.h
+++ b/chromium/ui/latency/mojo/latency_info_struct_traits.h
@@ -5,7 +5,6 @@
#ifndef UI_LATENCY_MOJO_LATENCY_INFO_STRUCT_TRAITS_H_
#define UI_LATENCY_MOJO_LATENCY_INFO_STRUCT_TRAITS_H_
-#include "mojo/common/common_custom_types_struct_traits.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
#include "ui/latency/latency_info.h"
#include "ui/latency/mojo/latency_info.mojom-shared.h"
diff --git a/chromium/ui/latency/stream_analyzer.cc b/chromium/ui/latency/stream_analyzer.cc
new file mode 100644
index 00000000000..2ecd094744a
--- /dev/null
+++ b/chromium/ui/latency/stream_analyzer.cc
@@ -0,0 +1,186 @@
+// 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/latency/stream_analyzer.h"
+
+namespace ui {
+namespace frame_metrics {
+
+StreamAnalyzer::StreamAnalyzer(
+ const StreamAnalyzerClient* client,
+ const SharedWindowedAnalyzerClient* shared_client,
+ std::vector<uint32_t> thresholds,
+ std::unique_ptr<Histogram> histogram)
+ : client_(client),
+ histogram_(std::move(histogram)),
+ windowed_analyzer_(client, shared_client) {
+ thresholds_.reserve(thresholds.size());
+ for (const uint32_t& t : thresholds)
+ thresholds_.emplace_back(t);
+}
+
+StreamAnalyzer::~StreamAnalyzer() = default;
+
+void StreamAnalyzer::Reset() {
+ StartNewReportPeriod();
+ windowed_analyzer_.ResetHistory();
+}
+
+void StreamAnalyzer::StartNewReportPeriod() {
+ histogram_->Reset();
+ windowed_analyzer_.ResetWorstValues();
+ for (auto& t : thresholds_)
+ t.ResetAccumulators();
+
+ total_weight_ = 0;
+ accumulator_ = 0;
+ root_accumulator_ = 0;
+ square_accumulator_ = Accumulator96b();
+}
+
+void StreamAnalyzer::AddSample(const uint32_t value, const uint32_t weight) {
+ DCHECK_GT(weight, 0u);
+
+ uint64_t weighted_value = static_cast<uint64_t>(weight) * value;
+ uint64_t weighted_root = weight * std::sqrt(static_cast<double>(value) *
+ kFixedPointRootMultiplier);
+ Accumulator96b weighted_square(value, weight);
+
+ // Verify overflow isn't an issue.
+ // square_accumulator_ has DCHECKs internally, so we don't worry about
+ // checking that here.
+ DCHECK_LT(weighted_value,
+ std::numeric_limits<decltype(accumulator_)>::max() - accumulator_);
+ DCHECK_LT(weighted_root,
+ std::numeric_limits<decltype(root_accumulator_)>::max() -
+ root_accumulator_);
+ DCHECK_LT(weight, std::numeric_limits<decltype(total_weight_)>::max() -
+ total_weight_);
+
+ histogram_->AddSample(value, weight);
+ windowed_analyzer_.AddSample(value, weight, weighted_value, weighted_root,
+ weighted_square);
+
+ for (auto& t : thresholds_) {
+ if (value >= t.threshold)
+ t.ge_weight += weight;
+ else
+ t.lt_weight += weight;
+ }
+
+ total_weight_ += weight;
+ accumulator_ += weighted_value;
+ root_accumulator_ += weighted_root;
+ square_accumulator_.Add(weighted_square);
+}
+
+double StreamAnalyzer::ComputeMean() const {
+ double result = static_cast<double>(accumulator_) / total_weight_;
+ return client_->TransformResult(result);
+}
+
+double StreamAnalyzer::ComputeRMS() const {
+ double mean_square = square_accumulator_.ToDouble() / total_weight_;
+ double result = std::sqrt(mean_square);
+ return client_->TransformResult(result);
+}
+
+double StreamAnalyzer::ComputeSMR() const {
+ double mean_root = static_cast<double>(root_accumulator_) / total_weight_;
+ double result = (mean_root * mean_root) / kFixedPointRootMultiplier;
+ return client_->TransformResult(result);
+}
+
+double StreamAnalyzer::VarianceHelper(double accum, double square_accum) const {
+ double mean = accum / total_weight_;
+ double mean_squared = mean * mean;
+ double mean_square = square_accum / total_weight_;
+ double variance = mean_square - mean_squared;
+ // This approach to calculating the standard deviation isn't numerically
+ // stable if the variance is very small relative to the mean, which might
+ // result in a negative variance. Clamp it to 0.
+ return std::max(0.0, variance);
+}
+
+double StreamAnalyzer::ComputeStdDev() const {
+ double variance =
+ VarianceHelper(accumulator_, square_accumulator_.ToDouble());
+ double std_dev = std::sqrt(variance);
+ return client_->TransformResult(std_dev);
+}
+
+double StreamAnalyzer::ComputeVarianceOfRoots() const {
+ double normalized_root =
+ static_cast<double>(root_accumulator_) / kFixedPointRootMultiplierSqrt;
+ double variance = VarianceHelper(normalized_root, accumulator_);
+ return client_->TransformResult(variance);
+}
+
+void StreamAnalyzer::ThresholdState::ResetAccumulators() {
+ ge_weight = 0;
+ lt_weight = 0;
+}
+
+std::vector<ThresholdResult> StreamAnalyzer::ComputeThresholds() const {
+ std::vector<ThresholdResult> results;
+ results.reserve(thresholds_.size());
+ for (const auto& t : thresholds_) {
+ double threshold = client_->TransformResult(t.threshold);
+ double ge_fraction =
+ static_cast<double>(t.ge_weight) / (t.ge_weight + t.lt_weight);
+ results.push_back({threshold, ge_fraction});
+ }
+ return results;
+}
+
+PercentileResults StreamAnalyzer::ComputePercentiles() const {
+ PercentileResults result;
+ result = histogram_->ComputePercentiles();
+ for (size_t i = 0; i < PercentileResults::kCount; i++) {
+ result.values[i] = client_->TransformResult(result.values[i]);
+ }
+ return result;
+}
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+StreamAnalyzer::AsValue() const {
+ auto state = std::make_unique<base::trace_event::TracedValue>();
+ AsValueInto(state.get());
+ return std::move(state);
+}
+
+void StreamAnalyzer::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetDouble("mean", ComputeMean());
+
+ state->SetDouble("rms", ComputeRMS());
+ state->SetDouble("smr", ComputeSMR());
+
+ state->SetDouble("std_dev", ComputeStdDev());
+ state->SetDouble("variance_of_roots", ComputeVarianceOfRoots());
+
+ state->BeginArray("percentiles");
+ PercentileResults result = ComputePercentiles();
+ for (size_t i = 0; i < PercentileResults::kCount; i++) {
+ state->BeginArray();
+ state->AppendDouble(PercentileResults::kPercentiles[i]);
+ state->AppendDouble(result.values[i]);
+ state->EndArray();
+ }
+ state->EndArray();
+
+ state->BeginArray("thresholds");
+ std::vector<ThresholdResult> thresholds(ComputeThresholds());
+ for (const auto& t : thresholds) {
+ state->BeginArray();
+ state->AppendDouble(t.threshold);
+ state->AppendDouble(t.ge_fraction);
+ state->EndArray();
+ }
+ state->EndArray();
+
+ windowed_analyzer_.AsValueInto(state);
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/stream_analyzer.h b/chromium/ui/latency/stream_analyzer.h
new file mode 100644
index 00000000000..45982fbb888
--- /dev/null
+++ b/chromium/ui/latency/stream_analyzer.h
@@ -0,0 +1,128 @@
+// 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_LATENCY_STREAM_ANALYZER_H_
+#define UI_LATENCY_STREAM_ANALYZER_H_
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/histograms.h"
+#include "ui/latency/windowed_analyzer.h"
+
+namespace ui {
+
+// Used to communicate fraction of time the value of a metric was greater than
+// or equal to the threshold.
+struct ThresholdResult {
+ double threshold = 0.0;
+ double ge_fraction = 0.0;
+};
+
+namespace frame_metrics {
+
+// The StreamAnalyzerClient interface is currently the same as
+// WindowedAnalyzerClient and can rely on the same implementation.
+using StreamAnalyzerClient = WindowedAnalyzerClient;
+
+// Tracks the overall mean, RMS, and SMR for a metric and also owns
+// the Histogram and WindowedAnalyzer.
+class StreamAnalyzer {
+ public:
+ StreamAnalyzer(const StreamAnalyzerClient* client,
+ const SharedWindowedAnalyzerClient* shared_client,
+ std::vector<uint32_t> thresholds,
+ std::unique_ptr<Histogram> histogram);
+ ~StreamAnalyzer();
+
+ // Resets all statistics and history.
+ void Reset();
+
+ // Resets the statistics without throwing away recent sample history in the
+ // WindowedAnalyzer.
+ void StartNewReportPeriod();
+
+ // To play well with the histogram range, |value| should be within the
+ // range [0,64000000]. If the units are milliseconds, that's 64 seconds.
+ // Otherwise, the histogram will clip the result.
+ // |weight| may be the duration the frame was active in microseconds
+ // or it may be 1 in case every frame is to be weighed equally.
+ void AddSample(const uint32_t value, const uint32_t weight);
+
+ // The mean, root-mean-squared, and squared-mean-root of all samples
+ // received since the last call to StartNewReportPeriod().
+ // The units are the same as the values added in AddSample().
+ double ComputeMean() const;
+ double ComputeRMS() const;
+ double ComputeSMR() const;
+
+ // StdDev calculates the standard deviation of all values in the stream.
+ // The units are the same as the values added in AddSample().
+ // The work to track this is the same as RMS, so we effectively get this for
+ // free. Given two of the Mean, RMS, and StdDev, we can calculate the third.
+ double ComputeStdDev() const;
+
+ // VarianceOfRoots calculates the variance of all square roots of values.
+ // The units end up being the same as the values added in AddSample().
+ // The work to track this is the same as SMR.
+ // Given two of the Mean, SMR, and VarianceOfRoots, we can calculate the
+ // third. Note: We don't track something like RootStdDevOfSquares since it
+ // would be difficult to track values raised to the fourth power.
+ // TODO(brianderon): Remove VarianceOfRoots if it's not useful.
+ double ComputeVarianceOfRoots() const;
+
+ // Thresholds returns a percentile for threshold values given to the
+ // constructor. This is useful for tracking improvements in really good
+ // sources, but it's dynamic range is limited, which prevents it from
+ // detecting improvements in sources where most of the frames are "bad".
+ std::vector<ThresholdResult> ComputeThresholds() const;
+
+ // CalculatePercentiles returns a value for certain percentiles.
+ // It is only an estimate, since the values are calculated from a histogram
+ // rather than from the entire history of actual values.
+ // This is useful for tracking improvements even in really bad sources
+ // since it's dynamic range includes all possible values.
+ PercentileResults ComputePercentiles() const;
+
+ // Expose the WindowedAnalyzer as const to make it's accessors
+ // available directly.
+ const WindowedAnalyzer& window() const { return windowed_analyzer_; }
+
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ protected:
+ double VarianceHelper(double accum, double square_accum) const;
+
+ struct ThresholdState {
+ explicit ThresholdState(uint32_t value) : threshold(value) {}
+ void ResetAccumulators();
+
+ uint32_t threshold;
+ uint32_t ge_weight = 0;
+ uint32_t lt_weight = 0;
+ };
+
+ const StreamAnalyzerClient* const client_;
+
+ std::vector<ThresholdState> thresholds_;
+ std::unique_ptr<Histogram> histogram_;
+ WindowedAnalyzer windowed_analyzer_;
+
+ uint64_t total_weight_ = 0;
+ uint64_t accumulator_ = 0;
+ uint64_t root_accumulator_ = 0;
+ Accumulator96b square_accumulator_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamAnalyzer);
+};
+
+} // namespace frame_metrics
+} // namespace ui
+
+#endif // UI_LATENCY_STREAM_ANALYZER_H_
diff --git a/chromium/ui/latency/stream_analyzer_unittest.cc b/chromium/ui/latency/stream_analyzer_unittest.cc
new file mode 100644
index 00000000000..08410961907
--- /dev/null
+++ b/chromium/ui/latency/stream_analyzer_unittest.cc
@@ -0,0 +1,312 @@
+// 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/latency/stream_analyzer.h"
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "ui/latency/frame_metrics_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+namespace {
+
+class StreamAnalyzerTest : public testing::Test {
+ public:
+ StreamAnalyzerTest() { NewAnalyzer(10, {2, 7, 10}); }
+
+ void SetUp() override {}
+
+ StreamAnalyzer* analyzer() { return analyzer_.get(); }
+
+ void NewAnalyzer(size_t window_size, std::vector<uint32_t> thresholds) {
+ shared_client_.max_window_size = window_size;
+ for (auto& t : thresholds) {
+ t *= kFixedPointMultiplier;
+ }
+ thresholds_ = std::move(thresholds);
+ std::unique_ptr<TestHistogram> histogram =
+ std::make_unique<TestHistogram>();
+ histogram_ = histogram.get();
+ analyzer_ = std::make_unique<StreamAnalyzer>(
+ &client_, &shared_client_, thresholds_, std::move(histogram));
+ }
+
+ protected:
+ size_t window_size;
+ TestStreamAnalyzerClient client_;
+ SharedWindowedAnalyzerClient shared_client_;
+ std::vector<uint32_t> thresholds_;
+ TestHistogram* histogram_;
+ std::unique_ptr<StreamAnalyzer> analyzer_;
+};
+
+TEST_F(StreamAnalyzerTest, AllResultsTheSame) {
+ // Try adding a single sample vs. multiple samples.
+ for (size_t samples : {1u, 100u}) {
+ // A power of 2 sweep for both the value and weight dimensions.
+ for (uint64_t value = 1; value < 0x100000000ULL; value *= 2) {
+ // Adding too many samples can result in overflow when multiplied by the
+ // weight. Divide by samples to avoid overflow.
+ for (uint64_t weight = 1; weight < 0x100000000ULL / samples;
+ weight *= 2) {
+ analyzer()->Reset();
+ AddSamplesHelper(analyzer(), value, weight, samples);
+ uint64_t expected_value =
+ value * TestStreamAnalyzerClient::result_scale;
+ EXPECT_EQ(expected_value, analyzer_->ComputeMean());
+ EXPECT_EQ(expected_value, analyzer_->ComputeRMS());
+ EXPECT_NEAR_SMR(analyzer_->ComputeSMR(), expected_value, weight);
+ EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev());
+ EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(),
+ expected_value, weight);
+
+ // Verify values are forwarded to the WindowedAnalyzer.
+ EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
+ EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
+ EXPECT_NEAR_SMR(expected_value,
+ analyzer_->window().ComputeWorstSMR().value, weight);
+ }
+ }
+ }
+
+ // All min/max combinations of value and weight.
+ for (uint64_t value : {0u, 0xFFFFFFFFu}) {
+ for (uint64_t weight : {1u, 0xFFFFFFFFu}) {
+ const size_t kSamplesToAdd = weight == 1 ? 100 : 1;
+ analyzer()->Reset();
+ AddSamplesHelper(analyzer(), value, weight, kSamplesToAdd);
+
+ // TestWindowedAnalyzerClient scales the result by 2.
+ uint64_t expected_value = value * TestStreamAnalyzerClient::result_scale;
+ // Makes sure our precision is good enough.
+ EXPECT_EQ(expected_value, analyzer_->ComputeMean());
+ EXPECT_EQ(expected_value, analyzer_->ComputeRMS());
+ EXPECT_NEAR_SMR(expected_value, analyzer_->ComputeSMR(), weight);
+ EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev());
+ EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(),
+ expected_value, weight);
+
+ // Verify values are forwarded to the WindowedAnalyzer.
+ EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
+ EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
+ EXPECT_NEAR_SMR(expected_value,
+ analyzer_->window().ComputeWorstSMR().value, weight);
+ }
+ }
+}
+
+// This applies a pattern of 2 values that are easy to calculate the expected
+// results for. It verifies the mean, rms, smr, standard deviation,
+// variance of the roots, and thresholds are calculated properly.
+// This doesn't check histogram or windowed analyzer related values since they
+// are tested separately and other unit tests verify their interactions
+// with StreamAnalyzer.
+TEST_F(StreamAnalyzerTest, AllResultsDifferent) {
+ const uint32_t kSampleWeight = 100;
+
+ const std::vector<uint32_t> pattern49 = {4, 9, 4, 9, 4, 9};
+ const std::vector<uint32_t> pattern4 = {4, 4, 4, 4, 4, 4};
+ const std::vector<uint32_t> pattern9 = {9, 9, 9, 9, 9, 9};
+
+ // Calculate the expected values for an equal number of 4's and 9's.
+ const double expected_mean = (4 + 9) * .5 * kFixedPointMultiplier *
+ TestStreamAnalyzerClient::result_scale;
+ const double expected_rms = std::sqrt((16 + 81) * .5) *
+ kFixedPointMultiplier *
+ TestStreamAnalyzerClient::result_scale;
+ const double mean_root = (2 + 3) * .5;
+ const double expected_smr = mean_root * mean_root * kFixedPointMultiplier *
+ TestStreamAnalyzerClient::result_scale;
+ const double expected_std_dev = (9 - 4) * .5 * kFixedPointMultiplier *
+ TestStreamAnalyzerClient::result_scale;
+ const double std_dev_of_roots = (3 - 2) * .5;
+ const double expected_variance_of_roots =
+ std_dev_of_roots * std_dev_of_roots * kFixedPointMultiplier *
+ TestStreamAnalyzerClient::result_scale;
+
+ std::vector<ThresholdResult> thresholds;
+
+ // Alternate 4 and 9.
+ for (size_t i = 0; i < 1000; i++) {
+ AddPatternHelper(&shared_client_, analyzer(), pattern49, kSampleWeight);
+ EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
+ EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
+ EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
+ EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
+ EXPECT_DOUBLE_EQ(expected_variance_of_roots,
+ analyzer_->ComputeVarianceOfRoots());
+ }
+ thresholds = analyzer_->ComputeThresholds();
+ ASSERT_EQ(3u, thresholds.size());
+ EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold);
+ EXPECT_EQ(1.0, thresholds[0].ge_fraction);
+ EXPECT_EQ(0.5, thresholds[1].ge_fraction);
+ EXPECT_EQ(0.0, thresholds[2].ge_fraction);
+
+ // 4's then 9's.
+ analyzer()->Reset();
+ for (size_t i = 0; i < 500; i++) {
+ AddPatternHelper(&shared_client_, analyzer(), pattern4, kSampleWeight);
+ }
+ for (size_t i = 0; i < 500; i++) {
+ AddPatternHelper(&shared_client_, analyzer(), pattern9, kSampleWeight);
+ }
+ thresholds = analyzer_->ComputeThresholds();
+ EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
+ EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
+ EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
+ EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
+ EXPECT_DOUBLE_EQ(expected_variance_of_roots,
+ analyzer_->ComputeVarianceOfRoots());
+ EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold);
+ EXPECT_EQ(1.0, thresholds[0].ge_fraction);
+ EXPECT_EQ(0.5, thresholds[1].ge_fraction);
+ EXPECT_EQ(0.0, thresholds[2].ge_fraction);
+
+ // 9's then 4's.
+ analyzer()->Reset();
+ for (size_t i = 0; i < 500; i++) {
+ AddPatternHelper(&shared_client_, analyzer(), pattern9, kSampleWeight);
+ }
+ for (size_t i = 0; i < 500; i++) {
+ AddPatternHelper(&shared_client_, analyzer(), pattern4, kSampleWeight);
+ }
+ thresholds = analyzer_->ComputeThresholds();
+ EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
+ EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
+ EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
+ EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
+ EXPECT_DOUBLE_EQ(expected_variance_of_roots,
+ analyzer_->ComputeVarianceOfRoots());
+ EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold);
+ EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold);
+ EXPECT_EQ(1.0, thresholds[0].ge_fraction);
+ EXPECT_EQ(0.5, thresholds[1].ge_fraction);
+ EXPECT_EQ(0.0, thresholds[2].ge_fraction);
+}
+
+TEST_F(StreamAnalyzerTest, SamplesForwardedToHistogram) {
+ const uint32_t kSampleWeight = 123;
+ const std::vector<uint32_t> pattern = {4, 9, 16, 25, 36, 49};
+ AddPatternHelper(&shared_client_, analyzer(), pattern, kSampleWeight);
+ std::vector<TestHistogram::ValueWeightPair> samples(
+ histogram_->GetAndResetAllAddedSamples());
+ ASSERT_EQ(pattern.size(), samples.size());
+ for (size_t i = 0; i < samples.size(); i++) {
+ EXPECT_EQ(pattern[i] * kFixedPointMultiplier, samples[i].value);
+ EXPECT_EQ(kSampleWeight, samples[i].weight);
+ }
+}
+
+TEST_F(StreamAnalyzerTest, PercentilesModifiedByClient) {
+ double result0 = 7;
+ double result1 = 11;
+ histogram_->SetResults({{result0, result1}});
+ PercentileResults results = analyzer()->ComputePercentiles();
+ EXPECT_EQ(client_.TransformResult(result0), results.values[0]);
+ EXPECT_EQ(client_.TransformResult(result1), results.values[1]);
+}
+
+// StreamAnalyzerNaive is a subset of stream analyzer that only uses single
+// precision floating point accumulators and can accumulate error.
+// This is used to verify patterns that accumulate error, so we can then verify
+// those patterns don't result in acculated error in the actual implementation.
+struct StreamAnalyzerNaive {
+ void AddSample(uint32_t value,
+ uint32_t weight,
+ uint64_t weighted_value,
+ uint64_t weighted_root,
+ const Accumulator96b& weighted_square) {
+ accumulator_ += static_cast<double>(weight) * value;
+ root_accumulator_ += static_cast<double>(weight) * std::sqrt(value);
+ square_accumulator_ += static_cast<double>(weight) * value * value;
+ total_weight_ += weight;
+ }
+
+ double ComputeMean() {
+ return client_.TransformResult(accumulator_ / total_weight_);
+ }
+ double ComputeRMS() {
+ return client_.TransformResult(
+ std::sqrt(square_accumulator_ / total_weight_));
+ }
+ double ComputeSMR() {
+ double mean_root = root_accumulator_ / total_weight_;
+ return client_.TransformResult(mean_root * mean_root);
+ }
+
+ float total_weight_ = 0;
+ float accumulator_ = 0;
+ float root_accumulator_ = 0;
+ float square_accumulator_ = 0;
+
+ TestStreamAnalyzerClient client_;
+};
+
+// Unlike the WindowedAnalyzer, there aren't patterns of input that would
+// affect the precision of our results very much with double precision floating
+// point accumulators. This is because we aren't subtracting values like the
+// WindowedAnalyzer does. Nevertheless, there can be issues if the accumulators
+// are only single precision.
+TEST_F(StreamAnalyzerTest, Precision) {
+ StreamAnalyzerNaive naive_analyzer;
+
+ uint32_t large_value = 20 * base::TimeTicks::kMicrosecondsPerSecond;
+ uint32_t large_weight = large_value;
+ size_t large_sample_count = 1;
+ AddSamplesHelper(&naive_analyzer, large_value, large_weight,
+ large_sample_count);
+ AddSamplesHelper(analyzer(), large_value, large_weight, large_sample_count);
+
+ uint32_t small_value = 1 * base::TimeTicks::kMicrosecondsPerMillisecond;
+ uint32_t small_weight = small_value;
+ size_t small_sample_count = 60 * 60 * 60; // 1hr of 60Hz frames.
+ AddSamplesHelper(&naive_analyzer, small_value, small_weight,
+ small_sample_count);
+ AddSamplesHelper(analyzer(), small_value, small_weight, small_sample_count);
+
+ double total_weight = static_cast<double>(large_sample_count) * large_weight +
+ static_cast<double>(small_sample_count) * small_weight;
+
+ double large_value_f = large_value;
+ double small_value_f = small_value;
+
+ double expected_mean = client_.TransformResult(
+ (large_value_f * large_weight +
+ small_sample_count * small_value_f * small_weight) /
+ total_weight);
+ EXPECT_ABS_LT(expected_mean * .001,
+ expected_mean - naive_analyzer.ComputeMean());
+ EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
+
+ double large_value_squared = large_value_f * large_value_f * large_weight;
+ double small_value_squared = small_value_f * small_value_f * small_weight;
+ double mean_square =
+ (large_value_squared + small_sample_count * small_value_squared) /
+ total_weight;
+ double expected_rms = client_.TransformResult(std::sqrt(mean_square));
+ EXPECT_ABS_LT(expected_rms * .001,
+ expected_rms - naive_analyzer.ComputeRMS());
+ EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
+
+ double large_value_root = std::sqrt(large_value_f) * large_weight;
+ double small_value_root = std::sqrt(small_value_f) * small_weight;
+ double mean_root =
+ (large_value_root + small_sample_count * small_value_root) / total_weight;
+ double expected_smr = client_.TransformResult(mean_root * mean_root);
+ EXPECT_ABS_LT(expected_smr * .001,
+ expected_smr - naive_analyzer.ComputeSMR());
+ EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), 1);
+}
+
+} // namespace
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/windowed_analyzer.cc b/chromium/ui/latency/windowed_analyzer.cc
new file mode 100644
index 00000000000..01e61c9b841
--- /dev/null
+++ b/chromium/ui/latency/windowed_analyzer.cc
@@ -0,0 +1,146 @@
+// 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/latency/windowed_analyzer.h"
+
+namespace ui {
+
+void FrameRegionResult::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetDouble("value", value);
+ state->SetDouble("start", window_begin.since_origin().InMillisecondsF());
+ state->SetDouble("duration", (window_end - window_begin).InMillisecondsF());
+}
+
+namespace frame_metrics {
+
+WindowedAnalyzer::WindowedAnalyzer(
+ const WindowedAnalyzerClient* client,
+ const SharedWindowedAnalyzerClient* shared_client)
+ : client_(client), shared_client_(shared_client) {
+ window_queue_.reserve(shared_client->max_window_size);
+}
+
+WindowedAnalyzer::~WindowedAnalyzer() = default;
+
+void WindowedAnalyzer::ResetWorstValues() {
+ results_.reset();
+}
+
+void WindowedAnalyzer::ResetHistory() {
+ total_weight_ = 0;
+ accumulator_ = 0;
+ root_accumulator_ = 0;
+ square_accumulator_ = Accumulator96b();
+ window_queue_.resize(0);
+}
+
+void WindowedAnalyzer::AddSample(uint32_t value,
+ uint32_t weight,
+ uint64_t weighted_value,
+ uint64_t weighted_root,
+ const Accumulator96b& weighted_square) {
+ DCHECK_GT(weight, 0u);
+ DCHECK_EQ(weighted_value, static_cast<uint64_t>(weight) * value);
+
+ // Remove old values from the accumulators.
+ if (window_queue_.size() >= shared_client_->max_window_size) {
+ const uint32_t old_value = window_queue_.front().value;
+ const uint32_t old_weight = window_queue_.front().weight;
+ window_queue_.pop_front();
+
+ // Re-calculate some of the old values here. Although squared and root are
+ // passed in, we've only stored the original value to reduce memory usage.
+ total_weight_ -= old_weight;
+ accumulator_ -= static_cast<uint64_t>(old_weight) * old_value;
+ // Casting the whole rhs is important to ensure rounding happens at a place
+ // equivalent to when it was added.
+ root_accumulator_ -= static_cast<uint64_t>(
+ old_weight *
+ std::sqrt(static_cast<uint64_t>(old_value) << kFixedPointRootShift));
+ square_accumulator_.Subtract(Accumulator96b(old_value, old_weight));
+ }
+
+ // Verify overflow isn't an issue.
+ // square_accumulator_ has DCHECKs internally, so we don't worry about
+ // checking that here.
+ DCHECK_LT(weighted_value,
+ std::numeric_limits<decltype(accumulator_)>::max() - accumulator_);
+ DCHECK_LT(weighted_root,
+ std::numeric_limits<decltype(root_accumulator_)>::max() -
+ root_accumulator_);
+ DCHECK_LT(weight, std::numeric_limits<decltype(total_weight_)>::max() -
+ total_weight_);
+
+ window_queue_.push_back({value, weight});
+ total_weight_ += weight;
+ accumulator_ += weighted_value;
+ root_accumulator_ += weighted_root;
+ square_accumulator_.Add(weighted_square);
+ if (window_queue_.size() >= shared_client_->max_window_size) {
+ bool initialize_results = !results_;
+ if (initialize_results)
+ results_.emplace();
+ UpdateWorst(accumulator_, &results_->mean, initialize_results);
+ UpdateWorst(root_accumulator_, &results_->root, initialize_results);
+ UpdateWorst(square_accumulator_, &results_->square, initialize_results);
+ }
+}
+
+FrameRegionResult WindowedAnalyzer::ComputeWorstMean() const {
+ FrameRegionResult result;
+ if (results_) {
+ result = results_->mean;
+ } else {
+ UpdateWorst(accumulator_, &result, true);
+ }
+ result.value = client_->TransformResult(result.value);
+ return result;
+}
+
+FrameRegionResult WindowedAnalyzer::ComputeWorstRMS() const {
+ FrameRegionResult result;
+ if (results_) {
+ result = results_->square;
+ } else {
+ UpdateWorst(square_accumulator_, &result, true);
+ }
+ result.value = client_->TransformResult(std::sqrt(result.value));
+ return result;
+}
+
+FrameRegionResult WindowedAnalyzer::ComputeWorstSMR() const {
+ FrameRegionResult result;
+ if (results_) {
+ result = results_->root;
+ } else {
+ UpdateWorst(root_accumulator_, &result, true);
+ }
+ result.value = client_->TransformResult((result.value * result.value) /
+ kFixedPointRootMultiplier);
+ return result;
+}
+
+void WindowedAnalyzer::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ FrameRegionResult region;
+
+ region = ComputeWorstMean();
+ state->BeginDictionary("worst_mean");
+ region.AsValueInto(state);
+ state->EndDictionary();
+
+ region = ComputeWorstSMR();
+ state->BeginDictionary("worst_smr");
+ region.AsValueInto(state);
+ state->EndDictionary();
+
+ region = ComputeWorstRMS();
+ state->BeginDictionary("worst_rms");
+ region.AsValueInto(state);
+ state->EndDictionary();
+}
+
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/latency/windowed_analyzer.h b/chromium/ui/latency/windowed_analyzer.h
new file mode 100644
index 00000000000..248b6cc446d
--- /dev/null
+++ b/chromium/ui/latency/windowed_analyzer.h
@@ -0,0 +1,161 @@
+// 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_LATENCY_WINDOWED_ANALYZER_H_
+#define UI_LATENCY_WINDOWED_ANALYZER_H_
+
+#include <cstdint>
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "ui/latency/fixed_point.h"
+
+namespace ui {
+
+// FrameRegionResult encodes window of time where a metric was worst.
+// The |sample_count| is the number of samples/frames within the time window
+// used to calculate the result. It is reported in case the client wants to
+// assess the confidence of the result.
+struct FrameRegionResult {
+ double value = 0;
+ size_t sample_count = 0;
+ base::TimeTicks window_begin;
+ base::TimeTicks window_end;
+
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+};
+
+namespace frame_metrics {
+
+// Client delegates that are specific to each WindowedAnalyzer.
+class WindowedAnalyzerClient {
+ public:
+ // The WorstMean,RMS,SMR methods will give TransformResult() a chance to
+ // modify the results via this delegate.
+ // This can be used to undo any tranformations applied to values added
+ // to AddSample, such as conversions to fixed point.
+ virtual double TransformResult(double result) const = 0;
+
+ // TODO(brianderson): Replace WindowedAnalyzer::window_queue_ with a client
+ // interface here. All latency derived metrics should be able to share a
+ // common history of values. http://crbug.com/822054
+};
+
+// Client delegates that can be shared by multiple WindowedAnalyzers.
+// Tracks the current window of time that can be stored as the worst
+// window of time if a metric detects it as such.
+struct SharedWindowedAnalyzerClient {
+ SharedWindowedAnalyzerClient() : max_window_size(0) {}
+
+ explicit SharedWindowedAnalyzerClient(size_t max_window_size)
+ : max_window_size(max_window_size) {}
+
+ SharedWindowedAnalyzerClient(size_t max_window_size,
+ base::TimeTicks window_begin,
+ base::TimeTicks window_end)
+ : max_window_size(max_window_size),
+ window_begin(window_begin),
+ window_end(window_end) {}
+
+ // Maximum window size in number of samples.
+ size_t max_window_size;
+
+ // Current window of time for the samples being added.
+ base::TimeTicks window_begin;
+ base::TimeTicks window_end;
+};
+
+// Detects the worst windows of time for a metric.
+// Tracks the current values of the current window of time for the
+// mean, RMS, and SMR of a single metric. It maintains a history
+// of the recent samples and, for each new sample, updates it's accumulators
+// using the oldest and newest samples, without looking at any of the other
+// samples in between.
+class WindowedAnalyzer {
+ public:
+ WindowedAnalyzer(const WindowedAnalyzerClient* client,
+ const SharedWindowedAnalyzerClient* shared_client);
+ virtual ~WindowedAnalyzer();
+
+ // ResetWosrtValues only resets the memory of worst values encountered,
+ // without resetting recent sample history.
+ void ResetWorstValues();
+
+ // ResetHistory only resets recent sample history without resetting memory
+ // of the worst values ecnountered.
+ void ResetHistory();
+
+ // Callers of AddSample will already have calculated weighted values to
+ // track cumulative results, so just let them pass in the values here
+ // rather than re-calculating them.
+ void AddSample(uint32_t value,
+ uint32_t weight,
+ uint64_t weighted_value,
+ uint64_t weighted_root,
+ const Accumulator96b& weighted_square);
+
+ // Returns the worst regions encountered so far.
+ FrameRegionResult ComputeWorstMean() const;
+ FrameRegionResult ComputeWorstRMS() const;
+ FrameRegionResult ComputeWorstSMR() const;
+
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ protected:
+ struct QueueEntry {
+ uint32_t value = 0;
+ uint32_t weight = 0;
+ };
+
+ // Updates the result with the current value, if it is worse than the
+ // value in |result| or if |initialize| is true.
+ template <typename AccumulatorT>
+ void UpdateWorst(const AccumulatorT& accumulator,
+ FrameRegionResult* result,
+ bool initialize) const {
+ double current_mean = AsDouble(accumulator) / total_weight_;
+ if (initialize || current_mean > result->value) {
+ result->value = current_mean;
+ result->sample_count = window_queue_.size();
+ result->window_begin = shared_client_->window_begin;
+ result->window_end = shared_client_->window_end;
+ }
+ }
+
+ const WindowedAnalyzerClient* const client_;
+ const SharedWindowedAnalyzerClient* const shared_client_;
+
+ // We need to maintain a history of values so we can
+ // remove old samples from the accumulators.
+ base::circular_deque<QueueEntry> window_queue_;
+
+ uint64_t total_weight_ = 0;
+ uint64_t accumulator_ = 0;
+ uint64_t root_accumulator_ = 0;
+ Accumulator96b square_accumulator_;
+
+ // Internal results that track the worst region so far.
+ // The time region is stored correctly, however the results are intermediate
+ // and must be adjusted by result_transform_ and fixed_point_multipler before
+ // exposure to the client. Furthermore, RMS needs to square root the result
+ // and SMR needs to square the result.
+ struct InternalResults {
+ FrameRegionResult mean;
+ FrameRegionResult root;
+ FrameRegionResult square;
+ };
+ // Optional since they aren't valid until we've seen enough samples.
+ // This delay prevents the first couple samples from dominating the result.
+ base::Optional<InternalResults> results_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowedAnalyzer);
+};
+
+} // namespace frame_metrics
+} // namespace ui
+
+#endif // UI_LATENCY_WINDOWED_ANALYZER_H_
diff --git a/chromium/ui/latency/windowed_analyzer_unittest.cc b/chromium/ui/latency/windowed_analyzer_unittest.cc
new file mode 100644
index 00000000000..71b42480548
--- /dev/null
+++ b/chromium/ui/latency/windowed_analyzer_unittest.cc
@@ -0,0 +1,470 @@
+// 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/latency/windowed_analyzer.h"
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/latency/frame_metrics_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+namespace {
+
+// Verify that the worst values for Mean, SMR, and RMS are all the same if
+// every value added is the same. Makes for a nice sanity check.
+TEST(FrameMetricsWindowedAnalyzerTest, AllResultsTheSame) {
+ // For this test, we don't care about the timeline, so just keep it constant.
+ TestWindowedAnalyzerClient client;
+ SharedWindowedAnalyzerClient shared_client(
+ 60, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+
+ // Try adding a single sample vs. multiple samples.
+ for (size_t samples : {1u, 100u}) {
+ // A power of 2 sweep for both the value and weight dimensions.
+ for (uint64_t value = 1; value < 0x100000000ULL; value *= 2) {
+ // Adding too many samples can result in overflow when multiplied by the
+ // weight. Divide by samples to avoid overflow.
+ for (uint64_t weight = 1; weight < 0x100000000ULL / samples;
+ weight *= 2) {
+ WindowedAnalyzer analyzer(&client, &shared_client);
+ AddSamplesHelper(&analyzer, value, weight, samples);
+ uint64_t expected_value =
+ value * TestWindowedAnalyzerClient::result_scale;
+ EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
+ << value << " x " << weight;
+ EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
+ << value << " x " << weight;
+ EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value,
+ weight)
+ << value << " x " << weight;
+ }
+ }
+ }
+
+ // All min/max combinations of value and weight.
+ for (uint64_t value : {0u, 0xFFFFFFFFu}) {
+ for (uint64_t weight : {1u, 0xFFFFFFFFu}) {
+ const size_t kSamplesToAdd = weight == 1 ? 100 : 1;
+ WindowedAnalyzer analyzer(&client, &shared_client);
+ AddSamplesHelper(&analyzer, value, weight, kSamplesToAdd);
+
+ // TestWindowedAnalyzerClient scales the result by 2.
+ uint64_t expected_value =
+ value * TestWindowedAnalyzerClient::result_scale;
+ // Makes sure our precision is good enough.
+ EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
+ << value << " x " << weight;
+ EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
+ << value << " x " << weight;
+ EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value, weight)
+ << value << " x " << weight;
+ }
+ }
+}
+
+// Verify that the worst values and their time regions are properly tracked
+// seperately for mean, SMR, and RMS.
+TEST(FrameMetricsWindowedAnalyzerTest, AllResultsDifferent) {
+ const size_t kMaxWindowSize = 6; // Same as the pattern length.
+ const uint32_t kSampleWeight = 100;
+
+ TestWindowedAnalyzerClient client;
+ SharedWindowedAnalyzerClient shared_client(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ WindowedAnalyzer analyzer(&client, &shared_client);
+
+ // Used to "clear" all the windowed accumulators.
+ const std::vector<uint32_t> pattern_clear = {0, 0, 0, 0, 0, 0};
+ // Worst mean pattern: mean of 3, smr of 1.5, rms of ~4.2.
+ const std::vector<uint32_t> pattern_max_mean = {0, 6, 0, 6, 0, 6};
+ double expected_worst_mean =
+ 3 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ // Lots of small janks maximizes the SMR.
+ // Worst SMR pattern: mean of 2, smr of 2, rms of 2.
+ const std::vector<uint32_t> pattern_max_smr = {2, 2, 2, 2, 2, 2};
+ double expected_worst_smr =
+ 2 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ // A few big janks dominate RMS.
+ // Worst RMS pattern: Mean of 2, smr of ~.3, rms of ~4.9
+ const std::vector<uint32_t> pattern_max_rms = {0, 0, 0, 0, 0, 12};
+ double expected_worst_rms = std::sqrt((12 * 12) / 6) * kFixedPointMultiplier *
+ TestWindowedAnalyzerClient::result_scale;
+
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_mean, kSampleWeight);
+ SharedWindowedAnalyzerClient worst_mean_client(shared_client);
+
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_smr, kSampleWeight);
+ SharedWindowedAnalyzerClient worst_smr_client(shared_client);
+
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_rms, kSampleWeight);
+ SharedWindowedAnalyzerClient worst_rms_client(shared_client);
+
+ // If there is a tie, the first window detected wins.
+ // This can go wrong if there's any accumulation of error because the
+ // values added aren't exactly the same as the values removed.
+ // This only catches accumulation of error in one direction, so isn't
+ // thorough, but it does help improve coverage.
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_mean, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_smr, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_max_rms, kSampleWeight);
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+
+ FrameRegionResult worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_worst_mean, worst_mean.value);
+ EXPECT_EQ(worst_mean_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(worst_mean_client.window_end, worst_mean.window_end);
+
+ FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_worst_smr, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(worst_smr_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(worst_smr_client.window_end, worst_smr.window_end);
+
+ FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_worst_rms, worst_rms.value);
+ EXPECT_EQ(worst_rms_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(worst_rms_client.window_end, worst_rms.window_end);
+}
+
+// Verify that the worst values and their time regions are properly tracked
+// even before a full window's worth is available.
+TEST(FrameMetricsWindowedAnalyzerTest, SmallSampleSize) {
+ const size_t kMaxWindowSize = 6; // Bigger than the pattern length.
+ const uint32_t kSampleWeight = 100;
+
+ TestWindowedAnalyzerClient client;
+ SharedWindowedAnalyzerClient shared_client(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ WindowedAnalyzer analyzer(&client, &shared_client);
+
+ const std::vector<uint32_t> pattern_short = {2, 2, 2};
+ double expected_initial_value =
+ 2 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ AddPatternHelper(&shared_client, &analyzer, pattern_short, kSampleWeight);
+ SharedWindowedAnalyzerClient short_client(shared_client);
+
+ FrameRegionResult worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
+ EXPECT_EQ(short_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_mean.window_end);
+
+ FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_smr.window_end);
+
+ FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+ EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_rms.window_end);
+}
+
+// Verify that a few bad values at the start don't dominate the result.
+TEST(FrameMetricsWindowedAnalyzerTest, BadFirstSamples) {
+ const size_t kMaxWindowSize = 6;
+ const uint32_t kSampleWeight = 100;
+ FrameRegionResult worst_mean, worst_smr, worst_rms;
+
+ TestWindowedAnalyzerClient client;
+ SharedWindowedAnalyzerClient shared_client(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ WindowedAnalyzer analyzer(&client, &shared_client);
+
+ // The 7's at the start will dominate the result if the implemenationd
+ // doesn't only start remembering the worst values after receiving at least
+ // a window's worth of samples.
+ const std::vector<uint32_t> pattern_short = {7, 7};
+ double expected_initial_value =
+ 7 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ AddPatternHelper(&shared_client, &analyzer, pattern_short, kSampleWeight);
+ SharedWindowedAnalyzerClient short_client(shared_client);
+
+ worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
+ EXPECT_EQ(short_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_mean.window_end);
+
+ worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_smr.window_end);
+
+ worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+ EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(short_client.window_end, worst_rms.window_end);
+
+ // Clear the window.
+ const std::vector<uint32_t> pattern_clear = {0, 0, 0, 0, 0, 0};
+ AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
+
+ // Make sure a new worst window with results less than 7 is detected.
+ const std::vector<uint32_t> pattern_long = {6, 6, 6, 6, 6, 6};
+ double expected_final_value =
+ 6 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ AddPatternHelper(&shared_client, &analyzer, pattern_long, kSampleWeight);
+ SharedWindowedAnalyzerClient long_client(shared_client);
+
+ worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_final_value, worst_mean.value);
+ EXPECT_EQ(long_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(long_client.window_end, worst_mean.window_end);
+
+ worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(long_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(long_client.window_end, worst_smr.window_end);
+
+ worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
+ EXPECT_EQ(long_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(long_client.window_end, worst_rms.window_end);
+}
+
+// Verify ResetAccumulators is continuous across the reset boundary.
+TEST(FrameMetricsWindowedAnalyzerTest, ResetWorstValues) {
+ const size_t kMaxWindowSize = 6; // Same as the pattern length.
+ const uint32_t kSampleWeight = 100;
+ FrameRegionResult worst_mean, worst_smr, worst_rms;
+
+ TestWindowedAnalyzerClient client;
+ SharedWindowedAnalyzerClient shared_client(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ WindowedAnalyzer analyzer(&client, &shared_client);
+
+ // Start off with the worst pattern.
+ const std::vector<uint32_t> pattern1 = {9, 9, 9, 9, 9, 9};
+ double expected_initial_value =
+ 9 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ AddPatternHelper(&shared_client, &analyzer, pattern1, kSampleWeight);
+ SharedWindowedAnalyzerClient initial_client(shared_client);
+
+ worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
+ EXPECT_EQ(initial_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
+
+ worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
+
+ worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+ EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
+
+ // The 4's below will affect the window, even after a reset, but
+ // won't affect the current worst values.
+ const std::vector<uint32_t> pattern2 = {4, 4, 4, 4, 4, 4};
+ AddPatternHelper(&shared_client, &analyzer, pattern2, kSampleWeight);
+
+ worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
+ EXPECT_EQ(initial_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
+
+ worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
+
+ worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+ EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
+
+ // Reset the worst value. This should not destroy sample history or
+ // any accumulators.
+ analyzer.ResetWorstValues();
+
+ // The first 4 below will be included with the previous 4's to detect an
+ // entire window of results, even though we've reset the worst values.
+ const std::vector<uint32_t> pattern3 = {4};
+ double expected_final_value =
+ 4 * kFixedPointMultiplier * TestWindowedAnalyzerClient::result_scale;
+ AddPatternHelper(&shared_client, &analyzer, pattern3, kSampleWeight);
+ SharedWindowedAnalyzerClient final_client(shared_client);
+
+ // Add a window of 1's here to verify it does not affect the window of 4's.
+ const std::vector<uint32_t> pattern4 = {1, 1, 1, 1, 1, 1};
+ AddPatternHelper(&shared_client, &analyzer, pattern4, kSampleWeight);
+
+ worst_mean = analyzer.ComputeWorstMean();
+ EXPECT_DOUBLE_EQ(expected_final_value, worst_mean.value);
+ EXPECT_EQ(final_client.window_begin, worst_mean.window_begin);
+ EXPECT_EQ(final_client.window_end, worst_mean.window_end);
+
+ worst_smr = analyzer.ComputeWorstSMR();
+ EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
+ EXPECT_EQ(final_client.window_begin, worst_smr.window_begin);
+ EXPECT_EQ(final_client.window_end, worst_smr.window_end);
+
+ worst_rms = analyzer.ComputeWorstRMS();
+ EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
+ EXPECT_EQ(final_client.window_begin, worst_rms.window_begin);
+ EXPECT_EQ(final_client.window_end, worst_rms.window_end);
+}
+
+// WindowedAnalyzerNaive is a version of WindowedAnalyzer that doesn't use
+// fixed point math and can accumulate error, even with double precision
+// accumulators. This is used to verify patterns that accumulate error without
+// fixed point math, so we can then verify those patterns don't result in
+// acculated error in the actual implementation.
+class WindowedAnalyzerNaive {
+ public:
+ WindowedAnalyzerNaive(size_t max_window_size)
+ : max_window_size_(max_window_size) {}
+
+ void AddSample(uint32_t value,
+ uint32_t weight,
+ uint64_t weighted_value,
+ uint64_t weighted_root,
+ const Accumulator96b& weighted_square) {
+ if (history_.size() >= max_window_size_) {
+ Sample old = history_.front();
+ history_.pop_front();
+ naive_accumulator_ -= static_cast<double>(old.weight) * old.value;
+ naive_root_accumulator_ -=
+ static_cast<double>(old.weight) * std::sqrt(old.value);
+ naive_square_accumulator_ -=
+ static_cast<double>(old.weight) * old.value * old.value;
+ naive_total_weight_ -= old.weight;
+ }
+
+ history_.push_back({value, weight});
+ naive_accumulator_ += static_cast<double>(weight) * value;
+ naive_root_accumulator_ += static_cast<double>(weight) * std::sqrt(value);
+ naive_square_accumulator_ += static_cast<double>(weight) * value * value;
+ naive_total_weight_ += weight;
+ }
+
+ struct Sample {
+ uint32_t value;
+ uint32_t weight;
+ };
+
+ const size_t max_window_size_;
+ double naive_accumulator_ = 0;
+ double naive_root_accumulator_ = 0;
+ double naive_square_accumulator_ = 0;
+ double naive_total_weight_ = 0;
+ base::circular_deque<Sample> history_;
+};
+
+// A version of the WindowedAnalyzer that allows us to inspect the internal
+// state for testing purposes.
+class TestWindowedAnalyzer : public WindowedAnalyzer {
+ public:
+ TestWindowedAnalyzer(const WindowedAnalyzerClient* client,
+ const SharedWindowedAnalyzerClient* shared_client)
+ : WindowedAnalyzer(client, shared_client) {}
+ ~TestWindowedAnalyzer() override {}
+
+ double CurrentAccumulator() { return accumulator_; }
+ double CurrentRootAccumulator() { return root_accumulator_; }
+ double CurrentSquareAccumulator() { return square_accumulator_.ToDouble(); }
+};
+
+// This test verifies that it's easy to blow the dynamic range of a floating
+// point accumulator with a particular pattern. Then it verifies that same
+// pattern does not result in error in the actual implementation.
+void TestNoAccumulatedPrecisionError(uint32_t big_value,
+ uint32_t small_value,
+ double naive_root_error_floor,
+ double naive_square_error_floor) {
+ const size_t kRuns = 1000;
+ const size_t kMaxWindowSize = 6; // Same as the pattern length.
+ const std::vector<uint32_t> pattern_clear = {0, 0, 0, 0, 0, 0};
+ const std::vector<uint32_t> pattern_bad = {big_value, small_value,
+ small_value, small_value,
+ small_value, small_value};
+
+ // Set up the actual WindowedAnalyzer implementation.
+ TestWindowedAnalyzerClient client_impl;
+ SharedWindowedAnalyzerClient shared_client_impl(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ TestWindowedAnalyzer analyzer_impl(&client_impl, &shared_client_impl);
+
+ // Set up the naive WindowedAnalyzer implementation.
+ SharedWindowedAnalyzerClient shared_client_naive(
+ kMaxWindowSize, base::TimeTicks(),
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1));
+ WindowedAnalyzerNaive analyzer_naive(kMaxWindowSize);
+
+ // Verify error keeps accumulating each time the bad pattern is applied.
+ // Note: We don't expect error in the mean accumulator since the values added
+ // are already truncated to whole integers before being passed in via
+ // AddSamples().
+ double naive_root_accumulator_prev = 0;
+ double naive_square_accumulator_prev = 0;
+ for (size_t i = 1; i <= kRuns; i++) {
+ AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_bad);
+ AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_clear);
+ EXPECT_EQ(0, analyzer_naive.naive_accumulator_);
+ EXPECT_ABS_LT(naive_root_accumulator_prev,
+ analyzer_naive.naive_root_accumulator_);
+ EXPECT_ABS_LT(naive_square_accumulator_prev,
+ analyzer_naive.naive_square_accumulator_);
+ naive_root_accumulator_prev = analyzer_naive.naive_root_accumulator_;
+ naive_square_accumulator_prev = analyzer_naive.naive_square_accumulator_;
+ }
+ // Verify naive error is bigger than some threshold after kRuns.
+ EXPECT_ABS_LE(naive_root_error_floor * kRuns,
+ analyzer_naive.naive_root_accumulator_);
+ EXPECT_ABS_LE(naive_square_error_floor * kRuns,
+ analyzer_naive.naive_square_accumulator_);
+
+ // Verify actual implementation has no error.
+ for (size_t i = 1; i <= kRuns; i++) {
+ AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_bad);
+ AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_clear);
+ EXPECT_EQ(0, analyzer_impl.CurrentAccumulator());
+ EXPECT_EQ(0, analyzer_impl.CurrentRootAccumulator());
+ EXPECT_EQ(0, analyzer_impl.CurrentSquareAccumulator());
+ }
+}
+
+// This is a synthetic example that is just outside the dynamic range of a
+// double accumulator. Doubles have 53 significand bits. When cubed, the
+// difference between the small and big values below require just over 53 bits.
+TEST(FrameMetricsWindowedAnalyzerTest, NoAccumulatedPrecisionErrorBasic) {
+ constexpr uint32_t big = 1 << 19;
+ constexpr uint32_t small = 2;
+ TestNoAccumulatedPrecisionError(big, small, 5e-8, 60);
+}
+
+// This is a more realistic scenario with orders of magnitude we are likely
+// to see in actual data. The error is small, but can become significant over
+// time.
+TEST(FrameMetricsWindowedAnalyzerTest, NoAccumulatedPrecisionErrorBig) {
+ constexpr uint32_t big = 1 * base::TimeTicks::kMicrosecondsPerSecond;
+ constexpr uint32_t small = 1 * base::TimeTicks::kMicrosecondsPerMillisecond;
+ TestNoAccumulatedPrecisionError(big, small, 7e-8, 256);
+}
+
+// This is a scenario with orders of magnitude that we can see in our data,
+// but that will be rare. Even after a single bad pattern, the error is
+// significant.
+TEST(FrameMetricsWindowedAnalyzerTest, NoAccumulatedPrecisionErrorBigger) {
+ constexpr uint32_t big = 20 * base::TimeTicks::kMicrosecondsPerSecond;
+ constexpr uint32_t small = 1 * base::TimeTicks::kMicrosecondsPerMillisecond;
+ TestNoAccumulatedPrecisionError(big, small, 2e-5, 1e6);
+}
+
+} // namespace
+} // namespace frame_metrics
+} // namespace ui
diff --git a/chromium/ui/login/account_picker/md_screen_account_picker.css b/chromium/ui/login/account_picker/md_screen_account_picker.css
index 39b9828bebf..258a6cad035 100644
--- a/chromium/ui/login/account_picker/md_screen_account_picker.css
+++ b/chromium/ui/login/account_picker/md_screen_account_picker.css
@@ -7,7 +7,8 @@
transition: width 180ms ease, height 180ms ease;
}
-#bubble {
+#bubble,
+#bubble-persistent {
margin-top: 16px;
z-index: 1;
}
@@ -45,6 +46,30 @@ html[dir=rtl] #signin-banner {
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;
@@ -55,6 +80,11 @@ 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;
@@ -117,4 +147,4 @@ html[screen=lock] #signin-banner.message-set {
.small-pod-container-mask.rotate {
transform: rotate(180deg);
-} \ No newline at end of file
+}
diff --git a/chromium/ui/login/account_picker/md_screen_account_picker.js b/chromium/ui/login/account_picker/md_screen_account_picker.js
index f143c032eb2..441f996b2fd 100644
--- a/chromium/ui/login/account_picker/md_screen_account_picker.js
+++ b/chromium/ui/login/account_picker/md_screen_account_picker.js
@@ -14,6 +14,14 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
*/
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',
@@ -30,6 +38,7 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
'hideUserPodCustomIcon',
'setUserPodFingerprintIcon',
'removeUserPodFingerprintIcon',
+ 'selectPodForDetachableBaseWarningBubble',
'setPinEnabledForUser',
'setAuthType',
'setTabletModeState',
@@ -173,6 +182,7 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
*/
onBeforeHide: function() {
$('pod-row').clearFocusedPod();
+ $('bubble-persistent').hide();
this.showing_ = false;
chrome.send('loginUIStateChanged', ['account-picker', false]);
$('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
@@ -205,11 +215,66 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
}
// Update the pod row display if incorrect password.
$('pod-row').setFocusedPodErrorDisplay(true);
- activatedPod.showBubble(error);
+
+ // 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.
* @param {boolean} showGuest Whether to show guest session button.
@@ -301,9 +366,10 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
* 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) {
- $('pod-row').showBannerMessage(message);
+ showBannerMessage: function(message, isWarning) {
+ $('pod-row').showBannerMessage(message, isWarning);
},
/**
diff --git a/chromium/ui/login/account_picker/md_user_pod_row.css b/chromium/ui/login/account_picker/md_user_pod_row.css
index eca51094800..75a143df1d3 100644
--- a/chromium/ui/login/account_picker/md_user_pod_row.css
+++ b/chromium/ui/login/account_picker/md_user_pod_row.css
@@ -33,13 +33,27 @@ pin-keyboard {
}
.pod .pin-container {
- left: 36px;
position: absolute;
- top: 300px;
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;
}
@@ -634,7 +648,7 @@ html[dir=rtl] .user-type-icon-area {
}
.fingerprint-icon-container.failed .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_failed.svg);
+ background-image: url(../../webui/resources/images/icon_error_outline.svg);
}
.action-box-menu {
diff --git a/chromium/ui/login/account_picker/md_user_pod_row.js b/chromium/ui/login/account_picker/md_user_pod_row.js
index 299342e0366..8d328140653 100644
--- a/chromium/ui/login/account_picker/md_user_pod_row.js
+++ b/chromium/ui/login/account_picker/md_user_pod_row.js
@@ -30,6 +30,7 @@ cr.define('login', function() {
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.
@@ -777,6 +778,15 @@ cr.define('login', function() {
*/
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;
@@ -1573,7 +1583,7 @@ cr.define('login', function() {
// 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 INTERVAL_REPEAT_MS = 10;
var input = this.mainInput;
var intervalId = setInterval(function() {
input.focus();
@@ -1674,30 +1684,64 @@ cr.define('login', function() {
},
/**
+ * 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.
- */
- showBubble: function(content) {
+ * @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 bubbleAnchor;
- var attachment;
- // Anchor the bubble to the input field.
- bubbleAnchor = this.getElementsByClassName('auth-container')[0];
- if (!bubbleAnchor) {
- console.error('auth-container not found!');
- bubbleAnchor = this.mainInput;
+ 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;
- 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.
@@ -1734,14 +1778,89 @@ cr.define('login', function() {
attachment = cr.ui.Bubble.Attachment.LEFT;
}
}
+
+ if (bubble == $('bubble'))
+ this.clearBubbleHideTimeout_();
+
+ var state = {shown: false, hidden: false};
+
var showBubbleCallback = function() {
this.removeEventListener('transitionend', showBubbleCallback);
- $('bubble').showContentForElement(
+ // 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_();
},
/**
@@ -1756,8 +1875,8 @@ cr.define('login', function() {
this.classList.toggle('signing-in', false);
if (takeFocus) {
if (!this.multiProfilesPolicyApplied) {
- // This will set a custom tab order.
- this.focusInput(true /*opt_ensureFocus*/);
+ this.focusInput(
+ this.mainInput.tagName == 'INPUT' /*opt_ensureFocus*/);
}
}
else
@@ -4067,7 +4186,12 @@ cr.define('login', function() {
var bannerContainer = $('signin-banner-container1');
if (bannerContainer.hidden)
return;
- bannerContainer.style.top = cr.ui.toCssPx(this.mainPod_.top / 2);
+ 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);
@@ -4211,11 +4335,13 @@ cr.define('login', function() {
* 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) {
+ 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_();
},
diff --git a/chromium/ui/login/account_picker/screen_account_picker.js b/chromium/ui/login/account_picker/screen_account_picker.js
index dd272b971c4..ed42b4a2c1f 100644
--- a/chromium/ui/login/account_picker/screen_account_picker.js
+++ b/chromium/ui/login/account_picker/screen_account_picker.js
@@ -21,506 +21,502 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
*/
var BUBBLE_POD_OFFSET = 4;
- return {
- EXTERNAL_API: [
- 'loadUsers',
- 'runAppForTesting',
- 'setApps',
- 'setShouldShowApps',
- 'showAppError',
- 'updateUserImage',
- 'setCapsLockState',
- 'forceLockedUserPodFocus',
- 'removeUser',
- 'showBannerMessage',
- 'showUserPodCustomIcon',
- 'hideUserPodCustomIcon',
- 'setUserPodFingerprintIcon',
- 'removeUserPodFingerprintIcon',
- 'setPinEnabledForUser',
- 'setAuthType',
- 'setTabletModeState',
- 'setPublicSessionDisplayName',
- 'setPublicSessionLocales',
- 'setPublicSessionKeyboardLayouts',
- 'setLockScreenAppsState',
- ],
-
- preferredWidth_: 0,
- preferredHeight_: 0,
-
- // Whether this screen is shown for the first time.
- firstShown_: true,
-
- // Whether this screen is currently being shown.
- showing_: false,
-
- // Last reported lock screen app activity state.
- lockScreenAppsState_: LOCK_SCREEN_APPS_STATE.NONE,
-
- /** @override */
- decorate: function() {
- login.PodRow.decorate($('pod-row'));
- this.ownerDocument.addEventListener('click',
- this.handleOwnerDocClick_.bind(this));
- },
-
- /** @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;
- },
-
- /**
- * When the account picker is being used to lock the screen, pressing the
- * exit accelerator key will sign out the active user as it would when
- * they are signed in.
- */
- exit: function() {
- // Check and disable the sign out button so that we can never have two
- // sign out requests generated in a row.
- if ($('pod-row').lockedPod && !$('sign-out-user-button').disabled) {
- $('sign-out-user-button').disabled = true;
- chrome.send('signOutUser');
- }
- },
-
- /* 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 = SIGNIN_UI_STATE.ACCOUNT_PICKER;
- // Header bar should be always visible on Account Picker screen.
- Oobe.getInstance().headerHidden = false;
- 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 = SIGNIN_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);
- },
-
- /**
- * Runs app with a given id from the list of loaded apps.
- * @param {!string} app_id of an app to run.
- * @param {boolean=} opt_diagnostic_mode Whether to run the app in
- * diagnostic mode. Default is false.
- */
- runAppForTesting: function(app_id, opt_diagnostic_mode) {
- $('pod-row').findAndRunAppForTesting(app_id, opt_diagnostic_mode);
- },
-
- /**
- * Adds given apps to the pod row.
- * @param {array} apps Array of apps.
- */
- setApps: function(apps) {
- $('pod-row').setApps(apps);
- },
-
- /**
- * Sets the flag of whether app pods should be visible.
- * @param {boolean} shouldShowApps Whether to show app pods.
- */
- setShouldShowApps: function(shouldShowApps) {
- $('pod-row').setShouldShowApps(shouldShowApps);
- },
-
- /**
- * Shows the given kiosk app error message.
- * @param {!string} message Error message to show.
- */
- showAppError: function(message) {
- // TODO(nkostylev): Figure out a way to show kiosk app launch error
- // pointing to the kiosk app pod.
- /** @const */ var BUBBLE_PADDING = 12;
- $('bubble').showTextForElement($('pod-row'),
- message,
- cr.ui.Bubble.Attachment.BOTTOM,
- $('pod-row').offsetWidth / 2,
- BUBBLE_PADDING);
- },
-
- /**
- * 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);
- },
-
- /**
- * Enforces focus on user pod of locked user.
- */
- forceLockedUserPodFocus: function() {
- var row = $('pod-row');
- if (row.lockedPod)
- row.focusPod(row.lockedPod, true);
- },
-
- /**
- * 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.
- */
- showBannerMessage: function(message) {
- 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);
- },
-
- /**
- * Updates UI based on the provided lock screen apps state.
- *
- * @param {LOCK_SCREEN_APPS_STATE} state The current lock screen apps state.
- */
- setLockScreenAppsState: function(state) {
- if (Oobe.getInstance().displayType != DISPLAY_TYPE.LOCK ||
- state == this.lockScreenAppsState_) {
- return;
- }
-
- this.lockScreenAppsState_ = state;
- $('login-header-bar').lockScreenAppsState = state;
- // When an lock screen app window is in background - i.e. visible behind
- // the lock screen UI - dim the lock screen background, so it's more
- // noticeable that the app widow in background is not actionable.
- $('background').classList.toggle(
- 'dimmed-background', state == LOCK_SCREEN_APPS_STATE.BACKGROUND);
-
- if (state === LOCK_SCREEN_APPS_STATE.FOREGROUND)
- $('pod-row').clearFocusedPod();
-
- },
-
- /**
- * Handles clicks on the document which displays the account picker UI.
- * If the click event target is outer container - i.e. background portion of
- * UI with no other UI elements, and lock screen apps are in background, a
- * request is issued to chrome to move lock screen apps to foreground.
- * @param {Event} event The click event.
- */
- handleOwnerDocClick_: function(event) {
- if (this.lockScreenAppsState_ != LOCK_SCREEN_APPS_STATE.BACKGROUND ||
- event.target != $('outer-container')) {
- return;
- }
- chrome.send('setLockScreenAppsState',
- [LOCK_SCREEN_APPS_STATE.FOREGROUND]);
-
- event.preventDefault();
- event.stopPropagation();
- },
- };
+ return {
+ EXTERNAL_API: [
+ 'loadUsers',
+ 'runAppForTesting',
+ 'setApps',
+ 'setShouldShowApps',
+ 'showAppError',
+ 'updateUserImage',
+ 'setCapsLockState',
+ 'forceLockedUserPodFocus',
+ 'removeUser',
+ 'showBannerMessage',
+ 'showUserPodCustomIcon',
+ 'hideUserPodCustomIcon',
+ 'setUserPodFingerprintIcon',
+ 'removeUserPodFingerprintIcon',
+ 'setPinEnabledForUser',
+ 'setAuthType',
+ 'setTabletModeState',
+ 'setPublicSessionDisplayName',
+ 'setPublicSessionLocales',
+ 'setPublicSessionKeyboardLayouts',
+ 'setLockScreenAppsState',
+ ],
+
+ preferredWidth_: 0,
+ preferredHeight_: 0,
+
+ // Whether this screen is shown for the first time.
+ firstShown_: true,
+
+ // Whether this screen is currently being shown.
+ showing_: false,
+
+ // Last reported lock screen app activity state.
+ lockScreenAppsState_: LOCK_SCREEN_APPS_STATE.NONE,
+
+ /** @override */
+ decorate: function() {
+ login.PodRow.decorate($('pod-row'));
+ this.ownerDocument.addEventListener(
+ 'click', this.handleOwnerDocClick_.bind(this));
+ },
+
+ /** @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;
+ },
+
+ /**
+ * When the account picker is being used to lock the screen, pressing the
+ * exit accelerator key will sign out the active user as it would when
+ * they are signed in.
+ */
+ exit: function() {
+ // Check and disable the sign out button so that we can never have two
+ // sign out requests generated in a row.
+ if ($('pod-row').lockedPod && !$('sign-out-user-button').disabled) {
+ $('sign-out-user-button').disabled = true;
+ chrome.send('signOutUser');
+ }
+ },
+
+ /* 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 = SIGNIN_UI_STATE.ACCOUNT_PICKER;
+ // Header bar should be always visible on Account Picker screen.
+ Oobe.getInstance().headerHidden = false;
+ 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 = SIGNIN_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);
+ },
+
+ /**
+ * Runs app with a given id from the list of loaded apps.
+ * @param {!string} app_id of an app to run.
+ * @param {boolean=} opt_diagnostic_mode Whether to run the app in
+ * diagnostic mode. Default is false.
+ */
+ runAppForTesting: function(app_id, opt_diagnostic_mode) {
+ $('pod-row').findAndRunAppForTesting(app_id, opt_diagnostic_mode);
+ },
+
+ /**
+ * Adds given apps to the pod row.
+ * @param {array} apps Array of apps.
+ */
+ setApps: function(apps) {
+ $('pod-row').setApps(apps);
+ },
+
+ /**
+ * Sets the flag of whether app pods should be visible.
+ * @param {boolean} shouldShowApps Whether to show app pods.
+ */
+ setShouldShowApps: function(shouldShowApps) {
+ $('pod-row').setShouldShowApps(shouldShowApps);
+ },
+
+ /**
+ * Shows the given kiosk app error message.
+ * @param {!string} message Error message to show.
+ */
+ showAppError: function(message) {
+ // TODO(nkostylev): Figure out a way to show kiosk app launch error
+ // pointing to the kiosk app pod.
+ /** @const */ var BUBBLE_PADDING = 12;
+ $('bubble').showTextForElement(
+ $('pod-row'), message, cr.ui.Bubble.Attachment.BOTTOM,
+ $('pod-row').offsetWidth / 2, BUBBLE_PADDING);
+ },
+
+ /**
+ * 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);
+ },
+
+ /**
+ * Enforces focus on user pod of locked user.
+ */
+ forceLockedUserPodFocus: function() {
+ var row = $('pod-row');
+ if (row.lockedPod)
+ row.focusPod(row.lockedPod, true);
+ },
+
+ /**
+ * 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);
+ },
+
+ /**
+ * Updates UI based on the provided lock screen apps state.
+ *
+ * @param {LOCK_SCREEN_APPS_STATE} state The current lock screen apps
+ * state.
+ */
+ setLockScreenAppsState: function(state) {
+ if (Oobe.getInstance().displayType != DISPLAY_TYPE.LOCK ||
+ state == this.lockScreenAppsState_) {
+ return;
+ }
+
+ this.lockScreenAppsState_ = state;
+ $('login-header-bar').lockScreenAppsState = state;
+ // When an lock screen app window is in background - i.e. visible behind
+ // the lock screen UI - dim the lock screen background, so it's more
+ // noticeable that the app widow in background is not actionable.
+ $('background')
+ .classList.toggle(
+ 'dimmed-background', state == LOCK_SCREEN_APPS_STATE.BACKGROUND);
+
+ if (state === LOCK_SCREEN_APPS_STATE.FOREGROUND)
+ $('pod-row').clearFocusedPod();
+
+ },
+
+ /**
+ * Handles clicks on the document which displays the account picker UI.
+ * If the click event target is outer container - i.e. background portion
+ * of UI with no other UI elements, and lock screen apps are in background,
+ * a request is issued to chrome to move lock screen apps to foreground.
+ * @param {Event} event The click event.
+ */
+ handleOwnerDocClick_: function(event) {
+ if (this.lockScreenAppsState_ != LOCK_SCREEN_APPS_STATE.BACKGROUND ||
+ event.target != $('outer-container')) {
+ return;
+ }
+ chrome.send(
+ 'setLockScreenAppsState', [LOCK_SCREEN_APPS_STATE.FOREGROUND]);
+
+ event.preventDefault();
+ event.stopPropagation();
+ },
+ };
});
diff --git a/chromium/ui/login/account_picker/user_pod_row.css b/chromium/ui/login/account_picker/user_pod_row.css
index 29bc6f66bf4..8ec451da2fa 100644
--- a/chromium/ui/login/account_picker/user_pod_row.css
+++ b/chromium/ui/login/account_picker/user_pod_row.css
@@ -575,7 +575,7 @@ html[dir=rtl] .user-type-icon-area {
}
.fingerprint-icon-container.failed .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_failed.svg);
+ background-image: url(../../webui/resources/images/icon_error_outline.svg);
}
.pod input[type='password'].hidden::-webkit-input-placeholder {
diff --git a/chromium/ui/login/bubble.js b/chromium/ui/login/bubble.js
index ff8d91a3220..13bebb738a3 100644
--- a/chromium/ui/login/bubble.js
+++ b/chromium/ui/login/bubble.js
@@ -55,6 +55,8 @@ cr.define('cr.ui', function() {
// Whether to hide bubble when key is pressed.
hideOnKeyPress_: true,
+ persistent_: false,
+
/** @override */
decorate: function() {
this.docKeyDownHandler_ = this.handleDocKeyDown_.bind(this);
@@ -93,6 +95,24 @@ cr.define('cr.ui', function() {
},
/**
+ * Whether the bubble should remain shown on user action events (e.g. on
+ * user clicking, or scrolling outside the bubble). Note that
+ * {@code this.hideOnKeyPress} has precedence.
+ * @type {boolean}
+ */
+ set persistent(value) {
+ this.persistent_ = value
+ },
+
+ /**
+ * If set, the element at which the bubble is anchored.
+ * @type {HTMLElement|undefined}
+ */
+ get anchor() {
+ return this.anchor_;
+ },
+
+ /**
* Element that should be focused on tab of last bubble element
* to create artificial closed tab-cycle through bubble.
* Same element as first focused on bubble opening.
@@ -218,9 +238,9 @@ cr.define('cr.ui', function() {
* @param {boolean=} opt_oldstyle Optional flag to force old style bubble,
* i.e. pre-MD-style.
*/
- showContentForElement: function(el, attachment, opt_content,
- opt_offset, opt_padding, opt_match_width,
- opt_oldstyle) {
+ showContentForElement: function(
+ el, attachment, opt_content, opt_offset, opt_padding, opt_match_width,
+ opt_oldstyle) {
/** @const */ var ARROW_OFFSET = 25;
/** @const */ var DEFAULT_PADDING = 18;
@@ -308,8 +328,8 @@ cr.define('cr.ui', function() {
* half of its weight/height.
* @param {number=} opt_padding Optional padding of the bubble.
*/
- showTextForElement: function(el, text, attachment,
- opt_offset, opt_padding) {
+ showTextForElement: function(
+ el, text, attachment, opt_offset, opt_padding) {
var span = this.ownerDocument.createElement('span');
span.textContent = text;
this.showContentForElement(el, attachment, span, opt_offset, opt_padding);
@@ -349,7 +369,7 @@ cr.define('cr.ui', function() {
* @private
*/
handleScroll_: function(e) {
- if (!this.hidden)
+ if (!this.hidden && !this.persistent_)
this.hide();
},
@@ -362,7 +382,7 @@ cr.define('cr.ui', function() {
if (e.target == this.anchor_)
return;
- if (!this.hidden)
+ if (!this.hidden && !this.persistent_)
this.hide();
},
@@ -391,10 +411,9 @@ cr.define('cr.ui', function() {
e.preventDefault();
}
// Close bubble on ESC or on hitting spacebar or Enter at close-button.
- if (e.key == Keys.ESC ||
- ((e.key == Keys.ENTER ||
- e.key == Keys.SPACE) &&
- e.target && e.target.classList.contains('close-button')))
+ if ((e.key == Keys.ESC && !this.persistent_) ||
+ ((e.key == Keys.ENTER || e.key == Keys.SPACE) && e.target &&
+ e.target.classList.contains('close-button')))
this.hide();
},
@@ -403,7 +422,7 @@ cr.define('cr.ui', function() {
* @private
*/
handleWindowBlur_: function(e) {
- if (!this.hidden)
+ if (!this.hidden && !this.persistent_)
this.hide();
}
};
diff --git a/chromium/ui/login/display_manager.js b/chromium/ui/login/display_manager.js
index 3102fbfef19..69b6d98443d 100644
--- a/chromium/ui/login/display_manager.js
+++ b/chromium/ui/login/display_manager.js
@@ -14,6 +14,7 @@
/** @const */ var SCREEN_OOBE_UPDATE = 'update';
/** @const */ var SCREEN_OOBE_RESET = 'reset';
/** @const */ var SCREEN_OOBE_ENROLLMENT = 'oauth-enrollment';
+/** @const */ var SCREEN_OOBE_DEMO_SETUP = 'demo-setup';
/** @const */ var SCREEN_OOBE_KIOSK_ENABLE = 'kiosk-enable';
/** @const */ var SCREEN_OOBE_AUTO_ENROLLMENT_CHECK = 'auto-enrollment-check';
/** @const */ var SCREEN_GAIA_SIGNIN = 'gaia-signin';
@@ -57,6 +58,7 @@
'app_launch_network_config';
/** @const */ var ACCELERATOR_BOOTSTRAPPING_SLAVE = "bootstrapping_slave";
/** @const */ var ACCELERATOR_DEMO_MODE = "demo_mode";
+/** @const */ var ACCELERATOR_SEND_FEEDBACK = "send_feedback";
/* Signin UI state constants. Used to control header bar UI. */
/** @const */ var SIGNIN_UI_STATE = {
@@ -383,12 +385,12 @@ cr.define('cr.ui.login', function() {
* @param {string} name Accelerator name.
*/
handleAccelerator: function(name) {
- if (this.currentScreen.ignoreAccelerators) {
+ if (this.currentScreen && this.currentScreen.ignoreAccelerators) {
return;
}
var currentStepId = this.screens_[this.currentStep_];
if (name == ACCELERATOR_CANCEL) {
- if (this.currentScreen.cancel) {
+ if (this.currentScreen && this.currentScreen.cancel) {
this.currentScreen.cancel();
}
} else if (name == ACCELERATOR_ENABLE_DEBBUGING) {
@@ -446,6 +448,8 @@ cr.define('cr.ui.login', function() {
-1) {
chrome.send('setupDemoMode');
}
+ } else if (name == ACCELERATOR_SEND_FEEDBACK) {
+ chrome.send('sendFeedback');
}
},
@@ -1015,14 +1019,14 @@ cr.define('cr.ui.login', function() {
};
/**
- * Shows sign-in error bubble.
- * @param {number} loginAttempts Number of login attemps tried.
- * @param {string} message Error message to show.
+ * Creates a div element used to display error message in an error bubble.
+ *
+ * @param {string} message The error message.
* @param {string} link Text to use for help link.
* @param {number} helpId Help topic Id associated with help link.
+ * @return {!HTMLElement} The error bubble content.
*/
- DisplayManager.showSignInError = function(loginAttempts, message, link,
- helpId) {
+ DisplayManager.createErrorElement_ = function(message, link, helpId) {
var error = document.createElement('div');
var messageDiv = document.createElement('div');
@@ -1044,6 +1048,19 @@ cr.define('cr.ui.login', function() {
}
error.setAttribute('aria-live', 'assertive');
+ return error;
+ };
+
+ /**
+ * Shows sign-in error bubble.
+ * @param {number} loginAttempts Number of login attemps tried.
+ * @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.showSignInError = function(
+ loginAttempts, message, link, helpId) {
+ var error = DisplayManager.createErrorElement_(message, link, helpId);
var currentScreen = Oobe.getInstance().currentScreen;
if (currentScreen && typeof currentScreen.showErrorBubble === 'function') {
@@ -1053,6 +1070,43 @@ 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);
+ }
+ };
+
+ /**
* Shows password changed screen that offers migration.
* @param {boolean} showError Whether to show the incorrect password error.
* @param {string} email What user does reauth. Being used for display in the
diff --git a/chromium/ui/login/md_screen_container.css b/chromium/ui/login/md_screen_container.css
index bdac3bbc5ad..c4ac19e2c26 100644
--- a/chromium/ui/login/md_screen_container.css
+++ b/chromium/ui/login/md_screen_container.css
@@ -22,19 +22,6 @@
perspective: 600px;
}
-.pin-container.pin-enabled {
- opacity: 1;
- transition: opacity 200ms ease-in-out 180ms;
- visibility: visible;
-}
-
-.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. */
-}
-
#scroll-container {
bottom: 0; /* Allows content overlap with control bar. */
left: 0;
diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn
index ed816055fb4..e7b7e35f858 100644
--- a/chromium/ui/message_center/BUILD.gn
+++ b/chromium/ui/message_center/BUILD.gn
@@ -13,12 +13,10 @@ aggregate_vector_icons("message_center_vector_icons") {
icon_directory = "vector_icons"
icons = [
- "notification_close_button.1x.icon",
"notification_close_button.icon",
"notification_expand_less.icon",
"notification_expand_more.icon",
"notification_inline_reply.icon",
- "notification_settings_button.1x.icon",
"notification_settings_button.icon",
"product.icon",
]
@@ -49,6 +47,7 @@ jumbo_component("message_center") {
"//ui/accessibility",
"//ui/display",
"//ui/events",
+ "//ui/events:gesture_detection",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/native_theme",
@@ -209,7 +208,7 @@ if (enable_message_center) {
":test_support",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gmock",
"//testing/gtest",
@@ -236,7 +235,7 @@ if (enable_message_center) {
if (is_chromeos) {
sources += [ "public/mojo/struct_traits_unittest.cc" ]
deps += [
- "//mojo/edk/system",
+ "//mojo/edk",
"//ui/message_center/public/mojo:test_interfaces",
]
}
diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc
index 53485f966a1..b5d9e1385b6 100644
--- a/chromium/ui/message_center/message_center_impl.cc
+++ b/chromium/ui/message_center/message_center_impl.cc
@@ -12,7 +12,6 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/observer_list.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -76,15 +75,6 @@ void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
NotificationList::PopupNotifications popups =
notification_list_->GetPopupNotifications(blockers_, &blocked);
- // Close already displayed pop-ups that are blocked now.
- for (const std::string& notification_id : blocked) {
- // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here
- // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown()
- // calls NotificationList::MarkSinglePopupAsShown(), but the whole cache
- // will be recreated below.
- if (FindVisibleNotificationById(notification_id)->IsRead())
- notification_list_->MarkSinglePopupAsShown(notification_id, true);
- }
visible_notifications_ =
notification_list_->GetVisibleNotifications(blockers_);
@@ -319,9 +309,9 @@ void MessageCenterImpl::ClickOnNotification(const std::string& id) {
scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
for (auto& observer : observer_list_)
- observer.OnNotificationClicked(id);
- if (delegate.get())
- delegate->Click();
+ observer.OnNotificationClicked(id, base::nullopt, base::nullopt);
+ if (delegate)
+ delegate->Click(base::nullopt, base::nullopt);
}
void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
@@ -336,9 +326,9 @@ void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
for (auto& observer : observer_list_)
- observer.OnNotificationButtonClicked(id, button_index);
- if (delegate.get())
- delegate->ButtonClick(button_index);
+ observer.OnNotificationClicked(id, button_index, base::nullopt);
+ if (delegate)
+ delegate->Click(button_index, base::nullopt);
}
void MessageCenterImpl::ClickOnNotificationButtonWithReply(
@@ -355,9 +345,9 @@ void MessageCenterImpl::ClickOnNotificationButtonWithReply(
scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
for (auto& observer : observer_list_)
- observer.OnNotificationButtonClickedWithReply(id, button_index, reply);
- if (delegate.get())
- delegate->ButtonClickWithReply(button_index, reply);
+ observer.OnNotificationClicked(id, button_index, reply);
+ if (delegate)
+ delegate->Click(button_index, reply);
}
void MessageCenterImpl::ClickOnSettingsButton(const std::string& id) {
diff --git a/chromium/ui/message_center/message_center_observer.h b/chromium/ui/message_center/message_center_observer.h
index 9ef0ec65c84..c88c1166571 100644
--- a/chromium/ui/message_center/message_center_observer.h
+++ b/chromium/ui/message_center/message_center_observer.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/optional.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/message_center_types.h"
@@ -34,20 +35,13 @@ class MESSAGE_CENTER_EXPORT MessageCenterObserver {
virtual void OnNotificationUpdated(const std::string& notification_id) {}
// Called when a click event happens on the notification associated with
- // |notification_id|.
- virtual void OnNotificationClicked(const std::string& notification_id) {}
-
- // Called when a click event happens on a button indexed by |button_index|
- // of the notification associated with |notification_id|.
- virtual void OnNotificationButtonClicked(const std::string& notification_id,
- int button_index) {}
-
- // Called when a click event happens on a button with an input indexed by
- // |button_index| of the notification associated with |notification_id|.
- virtual void OnNotificationButtonClickedWithReply(
+ // |notification_id|. |button_index| will be nullopt if the click occurred on
+ // the body of the notification. |reply| will be filled in only if there was
+ // an input field associated with the button.
+ virtual void OnNotificationClicked(
const std::string& notification_id,
- int button_index,
- const base::string16& reply) {}
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {}
// Called when notification settings button is clicked. The |handled| argument
// indicates whether the notification delegate already handled the operation.
diff --git a/chromium/ui/message_center/message_center_stats_collector.cc b/chromium/ui/message_center/message_center_stats_collector.cc
index 210e0bf85f5..c6503a3a9ed 100644
--- a/chromium/ui/message_center/message_center_stats_collector.cc
+++ b/chromium/ui/message_center/message_center_stats_collector.cc
@@ -92,24 +92,17 @@ void MessageCenterStatsCollector::OnNotificationUpdated(
}
void MessageCenterStatsCollector::OnNotificationClicked(
- const std::string& notification_id) {
- StatsCollection::iterator iter = stats_.find(notification_id);
- if (iter == stats_.end())
- return;
- NotificationStats& notification_stat = iter->second;
-
- notification_stat.CollectAction(NOTIFICATION_ACTION_CLICK);
-}
-
-void MessageCenterStatsCollector::OnNotificationButtonClicked(
const std::string& notification_id,
- int button_index) {
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {
StatsCollection::iterator iter = stats_.find(notification_id);
if (iter == stats_.end())
return;
NotificationStats& notification_stat = iter->second;
- notification_stat.CollectAction(NOTIFICATION_ACTION_BUTTON_CLICK);
+ notification_stat.CollectAction(button_index
+ ? NOTIFICATION_ACTION_BUTTON_CLICK
+ : NOTIFICATION_ACTION_CLICK);
}
void MessageCenterStatsCollector::OnNotificationSettingsClicked(bool handled) {
diff --git a/chromium/ui/message_center/message_center_stats_collector.h b/chromium/ui/message_center/message_center_stats_collector.h
index 6906f65d42f..c2e212c3111 100644
--- a/chromium/ui/message_center/message_center_stats_collector.h
+++ b/chromium/ui/message_center/message_center_stats_collector.h
@@ -66,9 +66,10 @@ class MessageCenterStatsCollector : public MessageCenterObserver {
void OnNotificationRemoved(const std::string& notification_id,
bool by_user) override;
void OnNotificationUpdated(const std::string& notification_id) override;
- void OnNotificationClicked(const std::string& notification_id) override;
- void OnNotificationButtonClicked(const std::string& notification_id,
- int button_index) override;
+ void OnNotificationClicked(
+ const std::string& notification_id,
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override;
void OnNotificationSettingsClicked(bool handled) override;
void OnNotificationDisplayed(const std::string& notification_id,
const DisplaySource source) override;
diff --git a/chromium/ui/message_center/notification_list.cc b/chromium/ui/message_center/notification_list.cc
index 03882443b45..a461bbff53f 100644
--- a/chromium/ui/message_center/notification_list.cc
+++ b/chromium/ui/message_center/notification_list.cc
@@ -34,7 +34,7 @@ bool ShouldShowNotificationAsPopup(
} // namespace
bool ComparePriorityTimestampSerial::operator()(Notification* n1,
- Notification* n2) {
+ Notification* n2) const {
if (n1->priority() > n2->priority()) // Higher pri go first.
return true;
if (n1->priority() < n2->priority())
@@ -42,7 +42,8 @@ bool ComparePriorityTimestampSerial::operator()(Notification* n1,
return CompareTimestampSerial()(n1, n2);
}
-bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) {
+bool CompareTimestampSerial::operator()(Notification* n1,
+ Notification* n2) const {
if (n1->timestamp() > n2->timestamp()) // Newer come first.
return true;
if (n1->timestamp() < n2->timestamp())
@@ -54,6 +55,11 @@ bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) {
return false;
}
+bool NotificationList::NotificationState::operator!=(
+ const NotificationState& other) const {
+ return shown_as_popup != other.shown_as_popup || is_read != other.is_read;
+}
+
NotificationList::NotificationList(MessageCenter* message_center)
: message_center_(message_center),
quiet_mode_(false) {
@@ -67,14 +73,13 @@ void NotificationList::SetNotificationsShown(
std::set<std::string>* updated_ids) {
Notifications notifications = GetVisibleNotifications(blockers);
- for (auto iter = notifications.begin(); iter != notifications.end(); ++iter) {
- Notification* notification = *iter;
- bool was_popup = notification->shown_as_popup();
- bool was_read = notification->IsRead();
+ for (Notification* notification : notifications) {
+ NotificationState* state = &GetNotification(notification->id())->second;
+ const NotificationState original_state = *state;
if (notification->priority() < SYSTEM_PRIORITY)
- notification->set_shown_as_popup(true);
- notification->set_is_read(true);
- if (updated_ids && !(was_popup && was_read))
+ state->shown_as_popup = true;
+ state->is_read = true;
+ if (updated_ids && (original_state != *state))
updated_ids->insert(notification->id());
}
}
@@ -91,17 +96,17 @@ void NotificationList::UpdateNotificationMessage(
if (iter == notifications_.end())
return;
- new_notification->CopyState(iter->get());
+ Notification* notification = iter->first.get();
+ NotificationState state = iter->second;
// Handles priority promotion. If the notification is already dismissed but
// the updated notification has higher priority, it should re-appear as a
// toast. Notifications coming from websites through the Web Notification API
// will always re-appear on update.
- if (((*iter)->priority() < new_notification->priority() ||
+ if ((notification->priority() < new_notification->priority() ||
new_notification->notifier_id().type == NotifierId::WEB_PAGE) &&
!quiet_mode_) {
- new_notification->set_is_read(false);
- new_notification->set_shown_as_popup(false);
+ state = NotificationState();
}
// Do not use EraseNotification and PushNotification, since we don't want to
@@ -110,7 +115,7 @@ void NotificationList::UpdateNotificationMessage(
// We really don't want duplicate IDs.
DCHECK(GetNotification(new_notification->id()) == notifications_.end());
- notifications_.insert(std::move(new_notification));
+ notifications_.emplace(std::move(new_notification), state);
}
void NotificationList::RemoveNotification(const std::string& id) {
@@ -120,9 +125,10 @@ void NotificationList::RemoveNotification(const std::string& id) {
NotificationList::Notifications NotificationList::GetNotificationsByNotifierId(
const NotifierId& notifier_id) {
Notifications notifications;
- for (const auto& notification : notifications_) {
+ for (const auto& tuple : notifications_) {
+ Notification* notification = tuple.first.get();
if (notification->notifier_id() == notifier_id)
- notifications.insert(notification.get());
+ notifications.insert(notification);
}
return notifications;
}
@@ -132,7 +138,7 @@ bool NotificationList::SetNotificationIcon(const std::string& notification_id,
auto iter = GetNotification(notification_id);
if (iter == notifications_.end())
return false;
- (*iter)->set_icon(image);
+ iter->first->set_icon(image);
return true;
}
@@ -141,7 +147,7 @@ bool NotificationList::SetNotificationImage(const std::string& notification_id,
auto iter = GetNotification(notification_id);
if (iter == notifications_.end())
return false;
- (*iter)->set_image(image);
+ iter->first->set_image(image);
return true;
}
@@ -151,7 +157,7 @@ bool NotificationList::SetNotificationButtonIcon(
auto iter = GetNotification(notification_id);
if (iter == notifications_.end())
return false;
- (*iter)->SetButtonIcon(button_index, image);
+ iter->first->SetButtonIcon(button_index, image);
return true;
}
@@ -161,16 +167,16 @@ bool NotificationList::HasNotificationOfType(const std::string& id,
if (iter == notifications_.end())
return false;
- return (*iter)->type() == type;
+ return iter->first->type() == type;
}
bool NotificationList::HasPopupNotifications(
const NotificationBlockers& blockers) {
- for (const auto& notification : notifications_) {
- if (notification->priority() < DEFAULT_PRIORITY)
+ for (const auto& tuple : notifications_) {
+ if (tuple.first->priority() < DEFAULT_PRIORITY)
break;
- if (!notification->shown_as_popup() &&
- ShouldShowNotificationAsPopup(*notification.get(), blockers)) {
+ if (!tuple.second.shown_as_popup &&
+ ShouldShowNotificationAsPopup(*tuple.first, blockers)) {
return true;
}
}
@@ -186,8 +192,9 @@ NotificationList::GetPopupNotifications(const NotificationBlockers& blockers,
// Collect notifications that should be shown as popups. Start from oldest.
for (auto iter = notifications_.rbegin(); iter != notifications_.rend();
iter++) {
- Notification* notification = iter->get();
- if (notification->shown_as_popup())
+ NotificationState* state = &iter->second;
+ Notification* notification = iter->first.get();
+ if (state->shown_as_popup)
continue;
// No popups for LOW/MIN priority.
@@ -195,6 +202,8 @@ NotificationList::GetPopupNotifications(const NotificationBlockers& blockers,
continue;
if (!ShouldShowNotificationAsPopup(*notification, blockers)) {
+ if (state->is_read)
+ state->shown_as_popup = true;
if (blocked)
blocked->push_back(notification->id());
continue;
@@ -218,17 +227,20 @@ void NotificationList::MarkSinglePopupAsShown(
auto iter = GetNotification(id);
DCHECK(iter != notifications_.end());
- if ((*iter)->shown_as_popup())
+ NotificationState* state = &iter->second;
+ const Notification& notification = *iter->first;
+
+ if (iter->second.shown_as_popup)
return;
// System notification is marked as shown only when marked as read.
- if ((*iter)->priority() != SYSTEM_PRIORITY || mark_notification_as_read)
- (*iter)->set_shown_as_popup(true);
+ if (notification.priority() != SYSTEM_PRIORITY || mark_notification_as_read)
+ state->shown_as_popup = true;
// The popup notification is already marked as read when it's displayed.
- // Set the is_read() back to false if necessary.
+ // Set the is_read back to false if necessary.
if (!mark_notification_as_read)
- (*iter)->set_is_read(false);
+ state->is_read = false;
}
void NotificationList::MarkSinglePopupAsDisplayed(const std::string& id) {
@@ -236,11 +248,12 @@ void NotificationList::MarkSinglePopupAsDisplayed(const std::string& id) {
if (iter == notifications_.end())
return;
- if ((*iter)->shown_as_popup())
+ NotificationState* state = &iter->second;
+
+ if (state->shown_as_popup)
return;
- if (!(*iter)->IsRead())
- (*iter)->set_is_read(true);
+ state->is_read = true;
}
NotificationDelegate* NotificationList::GetNotificationDelegate(
@@ -248,37 +261,37 @@ NotificationDelegate* NotificationList::GetNotificationDelegate(
auto iter = GetNotification(id);
if (iter == notifications_.end())
return nullptr;
- return (*iter)->delegate();
+ return iter->first->delegate();
}
void NotificationList::SetQuietMode(bool quiet_mode) {
quiet_mode_ = quiet_mode;
if (quiet_mode_) {
- for (auto& notification : notifications_)
- notification->set_shown_as_popup(true);
+ for (auto& tuple : notifications_)
+ tuple.second.shown_as_popup = true;
}
}
Notification* NotificationList::GetNotificationById(const std::string& id) {
auto iter = GetNotification(id);
if (iter != notifications_.end())
- return iter->get();
+ return iter->first.get();
return nullptr;
}
NotificationList::Notifications NotificationList::GetVisibleNotifications(
const NotificationBlockers& blockers) const {
Notifications result;
- for (const auto& notification : notifications_) {
+ for (const auto& tuple : notifications_) {
bool should_show = true;
for (size_t i = 0; i < blockers.size(); ++i) {
- if (!blockers[i]->ShouldShowNotification(*notification.get())) {
+ if (!blockers[i]->ShouldShowNotification(*tuple.first)) {
should_show = false;
break;
}
}
if (should_show)
- result.insert(notification.get());
+ result.insert(tuple.first.get());
}
return result;
@@ -293,7 +306,7 @@ NotificationList::OwnedNotifications::iterator
NotificationList::GetNotification(const std::string& id) {
for (auto iter = notifications_.begin(); iter != notifications_.end();
++iter) {
- if ((*iter)->id() == id)
+ if (iter->first->id() == id)
return iter;
}
return notifications_.end();
@@ -308,24 +321,19 @@ void NotificationList::PushNotification(
// Ensure that notification.id is unique by erasing any existing
// notification with the same id (shouldn't normally happen).
auto iter = GetNotification(notification->id());
- bool state_inherited = false;
+ NotificationState state;
if (iter != notifications_.end()) {
- notification->CopyState(iter->get());
- state_inherited = true;
+ state = iter->second;
EraseNotification(iter);
- }
- // Add the notification to the the list and mark it unread and unshown.
- if (!state_inherited) {
+ } else {
// TODO(mukai): needs to distinguish if a notification is dismissed by
// the quiet mode or user operation.
- notification->set_is_read(false);
- notification->set_shown_as_popup(message_center_->IsMessageCenterVisible()
- || quiet_mode_
- || notification->shown_as_popup());
+ state.shown_as_popup =
+ message_center_->IsMessageCenterVisible() || quiet_mode_;
}
- // Take ownership. The notification can only be removed from the list
- // in EraseNotification(), which will delete it.
- notifications_.insert(std::move(notification));
+ if (notification->priority() == MIN_PRIORITY)
+ state.is_read = true;
+ notifications_.emplace(std::move(notification), state);
}
} // namespace message_center
diff --git a/chromium/ui/message_center/notification_list.h b/chromium/ui/message_center/notification_list.h
index c5a7935e93f..21a07abfc37 100644
--- a/chromium/ui/message_center/notification_list.h
+++ b/chromium/ui/message_center/notification_list.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <list>
+#include <map>
#include <set>
#include <string>
@@ -37,18 +38,19 @@ struct NotifierId;
// Comparers used to auto-sort the lists of Notifications.
struct MESSAGE_CENTER_EXPORT ComparePriorityTimestampSerial {
- bool operator()(Notification* n1, Notification* n2);
+ bool operator()(Notification* n1, Notification* n2) const;
};
struct MESSAGE_CENTER_EXPORT CompareTimestampSerial {
- bool operator()(Notification* n1, Notification* n2);
+ bool operator()(Notification* n1, Notification* n2) const;
};
// An adapter to allow use of the comparers above with std::unique_ptr.
template <typename PlainCompare>
struct UniquePtrCompare {
template <typename T>
- bool operator()(const std::unique_ptr<T>& n1, const std::unique_ptr<T>& n2) {
+ bool operator()(const std::unique_ptr<T>& n1,
+ const std::unique_ptr<T>& n2) const {
return PlainCompare()(n1.get(), n2.get());
}
};
@@ -56,11 +58,19 @@ struct UniquePtrCompare {
// A helper class to manage the list of notifications.
class MESSAGE_CENTER_EXPORT NotificationList {
public:
+ struct NotificationState {
+ bool operator!=(const NotificationState& other) const;
+
+ bool shown_as_popup = false;
+ bool is_read = false;
+ };
+
// Auto-sorted set. Matches the order in which Notifications are shown in
// Notification Center.
using Notifications = std::set<Notification*, ComparePriorityTimestampSerial>;
using OwnedNotifications =
- std::set<std::unique_ptr<Notification>,
+ std::map<std::unique_ptr<Notification>,
+ NotificationState,
UniquePtrCompare<ComparePriorityTimestampSerial>>;
// Auto-sorted set used to return the Notifications to be shown as popup
@@ -139,6 +149,8 @@ class MESSAGE_CENTER_EXPORT NotificationList {
// NULL. Notification instance is owned by this list.
Notification* GetNotificationById(const std::string& id);
+ void PopupBlocked(const std::string& id);
+
// Returns all visible notifications, in a (priority-timestamp) order.
// Suitable for rendering notifications in a MessageCenter.
Notifications GetVisibleNotifications(
diff --git a/chromium/ui/message_center/notification_list_unittest.cc b/chromium/ui/message_center/notification_list_unittest.cc
index 995358660d6..98ee4f841b2 100644
--- a/chromium/ui/message_center/notification_list_unittest.cc
+++ b/chromium/ui/message_center/notification_list_unittest.cc
@@ -24,6 +24,8 @@ using base::UTF8ToUTF16;
namespace message_center {
+using NotificationState = NotificationList::NotificationState;
+
class NotificationListTest : public testing::Test {
public:
NotificationListTest() {}
@@ -90,7 +92,13 @@ class NotificationListTest : public testing::Test {
auto iter = notification_list()->GetNotification(id);
if (iter == notification_list()->notifications_.end())
return NULL;
- return iter->get();
+ return iter->first.get();
+ }
+
+ NotificationState GetNotificationState(const std::string& id) {
+ auto iter = notification_list()->GetNotification(id);
+ EXPECT_FALSE(iter == notification_list()->notifications_.end());
+ return iter->second;
}
NotificationList* notification_list() { return notification_list_.get(); }
@@ -191,8 +199,8 @@ TEST_F(NotificationListTest, UpdateNotificationWithPriority) {
std::string old_id;
auto old_notification = MakeNotification(&old_id);
old_notification->set_priority(DEFAULT_PRIORITY);
- old_notification->set_shown_as_popup(true);
notification_list()->AddNotification(std::move(old_notification));
+ notification_list()->MarkSinglePopupAsShown(old_id, true);
EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
std::string new_id;
@@ -210,8 +218,14 @@ TEST_F(NotificationListTest, UpdateNotificationWithPriority) {
// again.
// In quiet mode, |shown_as_popup| should not be reset , as popup should not
// be shown even though the priority is promoted.
- EXPECT_EQ(static_cast<bool>(quiet_mode),
- (*notifications.begin())->shown_as_popup());
+ const NotificationList::PopupNotifications popup_notifications =
+ notification_list()->GetPopupNotifications(blockers(), nullptr);
+ if (quiet_mode) {
+ ASSERT_EQ(0U, popup_notifications.size());
+ } else {
+ ASSERT_EQ(1U, popup_notifications.size());
+ EXPECT_EQ(new_id, (*popup_notifications.begin())->id());
+ }
}
}
@@ -576,15 +590,15 @@ TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) {
EXPECT_EQ(2u, GetPopupCounts());
- const Notification* n1 = GetNotification(id1);
- EXPECT_FALSE(n1->shown_as_popup());
- EXPECT_TRUE(n1->IsRead());
+ NotificationState n1_state = GetNotificationState(id1);
+ EXPECT_FALSE(n1_state.shown_as_popup);
+ EXPECT_TRUE(n1_state.is_read);
notification_list()->MarkSinglePopupAsShown(id1, true);
- n1 = GetNotification(id1);
- EXPECT_TRUE(n1->shown_as_popup());
- EXPECT_TRUE(n1->IsRead());
+ n1_state = GetNotificationState(id1);
+ EXPECT_TRUE(n1_state.shown_as_popup);
+ EXPECT_TRUE(n1_state.is_read);
const std::string replaced("test-replaced-id");
std::unique_ptr<Notification> notification(new Notification(
@@ -593,11 +607,11 @@ TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) {
NotifierId(NotifierId::APPLICATION, kExtensionId), RichNotificationData(),
NULL));
notification_list()->UpdateNotificationMessage(id1, std::move(notification));
- n1 = GetNotification(id1);
+ Notification* n1 = GetNotification(id1);
EXPECT_TRUE(n1 == NULL);
- const Notification* nr = GetNotification(replaced);
- EXPECT_TRUE(nr->shown_as_popup());
- EXPECT_TRUE(nr->IsRead());
+ const NotificationState nr_state = GetNotificationState(replaced);
+ EXPECT_TRUE(nr_state.shown_as_popup);
+ EXPECT_TRUE(nr_state.is_read);
}
TEST_F(NotificationListTest, QuietMode) {
@@ -616,19 +630,6 @@ TEST_F(NotificationListTest, QuietMode) {
// TODO(mukai): Add test of quiet mode with expiration.
}
-TEST_F(NotificationListTest, TestPushingShownNotification) {
- // Create a notification and mark it as shown.
- std::string id1;
- std::unique_ptr<Notification> notification(MakeNotification(&id1));
- notification->set_shown_as_popup(true);
-
- // Call PushNotification on this notification.
- notification_list()->PushNotification(std::move(notification));
-
- // Ensure it is still marked as shown.
- EXPECT_TRUE(GetNotification(id1)->shown_as_popup());
-}
-
TEST_F(NotificationListTest, TestHasNotificationOfType) {
std::string id = AddNotification();
diff --git a/chromium/ui/message_center/public/cpp/notification.cc b/chromium/ui/message_center/public/cpp/notification.cc
index dd06417bce3..dce03cfdb17 100644
--- a/chromium/ui/message_center/public/cpp/notification.cc
+++ b/chromium/ui/message_center/public/cpp/notification.cc
@@ -61,7 +61,7 @@ RichNotificationData::RichNotificationData(const RichNotificationData& other) =
RichNotificationData::~RichNotificationData() = default;
-Notification::Notification() = default;
+Notification::Notification() : serial_number_(g_next_serial_number++) {}
Notification::Notification(NotificationType type,
const std::string& id,
@@ -83,8 +83,6 @@ Notification::Notification(NotificationType type,
notifier_id_(notifier_id),
optional_fields_(optional_fields),
serial_number_(g_next_serial_number++),
- shown_as_popup_(false),
- is_read_(false),
delegate_(std::move(delegate)) {}
Notification::Notification(const std::string& id, const Notification& other)
@@ -121,18 +119,6 @@ std::unique_ptr<Notification> Notification::DeepCopy(
return notification_copy;
}
-bool Notification::IsRead() const {
- return is_read_ || optional_fields_.priority == MIN_PRIORITY;
-}
-
-void Notification::CopyState(Notification* base) {
- shown_as_popup_ = base->shown_as_popup();
- is_read_ = base->is_read_;
- if (!delegate_.get())
- delegate_ = base->delegate();
- optional_fields_.never_timeout = base->never_timeout();
-}
-
void Notification::SetButtonIcon(size_t index, const gfx::Image& icon) {
if (index >= optional_fields_.buttons.size())
return;
@@ -185,7 +171,6 @@ std::unique_ptr<Notification> Notification::CreateSystemNotification(
RichNotificationData(),
new HandleNotificationClickDelegate(click_callback), gfx::kNoneIcon,
SystemNotificationWarningLevel::CRITICAL_WARNING);
- notification->set_clickable(true);
notification->SetSystemPriority();
return notification;
}
@@ -227,10 +212,12 @@ std::unique_ptr<Notification> Notification::CreateSystemNotification(
}
// static
-void RegisterVectorIcon(const gfx::VectorIcon& vector_icon) {
- g_vector_icon_registry.Get().insert(
- std::pair<std::string, const gfx::VectorIcon&>(vector_icon.name,
- vector_icon));
+void RegisterVectorIcons(
+ const std::vector<const gfx::VectorIcon*>& vector_icons) {
+ for (const gfx::VectorIcon* icon : vector_icons) {
+ g_vector_icon_registry.Get().insert(
+ std::pair<std::string, const gfx::VectorIcon&>(icon->name, *icon));
+ }
}
// static
diff --git a/chromium/ui/message_center/public/cpp/notification.h b/chromium/ui/message_center/public/cpp/notification.h
index c91d0dac645..bbe62a47f33 100644
--- a/chromium/ui/message_center/public/cpp/notification.h
+++ b/chromium/ui/message_center/public/cpp/notification.h
@@ -145,9 +145,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData {
// depending on visual assistance systems.
bool should_make_spoken_feedback_for_popup_updates = true;
- // Whether it should be possible for the user to click on the notification.
- bool clickable = false;
-
#if defined(OS_CHROMEOS)
// Flag if the notification is pinned. If true, the notification is pinned
// and the user can't remove it.
@@ -240,10 +237,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
bool include_small_image,
bool include_icon_images);
- // Copies the internal on-memory state from |base|, i.e. shown_as_popup,
- // is_read and never_timeout.
- void CopyState(Notification* base);
-
NotificationType type() const { return type_; }
void set_type(NotificationType type) { type_ = type; }
@@ -372,15 +365,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
}
void SetButtonIcon(size_t index, const gfx::Image& icon);
- bool shown_as_popup() const { return shown_as_popup_; }
- void set_shown_as_popup(bool shown_as_popup) {
- shown_as_popup_ = shown_as_popup;
- }
-
- // Read status in the message center.
- bool IsRead() const;
- void set_is_read(bool read) { is_read_ = read; }
-
// Used to keep the order of notifications with the same timestamp.
// The notification with lesser serial_number is considered 'older'.
unsigned serial_number() { return serial_number_; }
@@ -391,9 +375,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
optional_fields_.never_timeout = never_timeout;
}
- bool clickable() const { return optional_fields_.clickable; }
- void set_clickable(bool clickable) { optional_fields_.clickable = clickable; }
-
bool pinned() const {
#if defined(OS_CHROMEOS)
return optional_fields_.pinned;
@@ -442,11 +423,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// method explicitly, to avoid setting it accidentally.
void SetSystemPriority();
- // Delegate actions.
- void Click() const { delegate()->Click(); }
- void ButtonClick(int index) const { delegate()->ButtonClick(index); }
- void Close(bool by_user) const { delegate()->Close(by_user); }
-
// Helper method to create a simple system notification. |click_callback|
// will be invoked when the notification is clicked.
//
@@ -512,8 +488,6 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// TODO(estade): these book-keeping fields should be moved into
// NotificationList.
unsigned serial_number_;
- bool shown_as_popup_; // True if this has been shown as a popup.
- bool is_read_; // True if this has been seen in the message center.
// A proxy object that allows access back to the JavaScript object that
// represents the notification, for firing events.
@@ -525,7 +499,8 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// of icons it expects to see, this allows for icon lookup without
// serialization/deserialization.
MESSAGE_CENTER_PUBLIC_EXPORT
-void RegisterVectorIcon(const gfx::VectorIcon& vector_icon);
+void RegisterVectorIcons(
+ const std::vector<const gfx::VectorIcon*>& vector_icon);
MESSAGE_CENTER_PUBLIC_EXPORT
const gfx::VectorIcon* GetRegisteredVectorIcon(const std::string& id);
diff --git a/chromium/ui/message_center/public/cpp/notification_delegate.cc b/chromium/ui/message_center/public/cpp/notification_delegate.cc
index 42b536b97ac..267b2155a7e 100644
--- a/chromium/ui/message_center/public/cpp/notification_delegate.cc
+++ b/chromium/ui/message_center/public/cpp/notification_delegate.cc
@@ -20,21 +20,11 @@ void ThunkNotificationDelegate::Close(bool by_user) {
impl_->Close(by_user);
}
-void ThunkNotificationDelegate::Click() {
+void ThunkNotificationDelegate::Click(
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {
if (impl_)
- impl_->Click();
-}
-
-void ThunkNotificationDelegate::ButtonClick(int button_index) {
- if (impl_)
- impl_->ButtonClick(button_index);
-}
-
-void ThunkNotificationDelegate::ButtonClickWithReply(
- int button_index,
- const base::string16& reply) {
- if (impl_)
- impl_->ButtonClickWithReply(button_index, reply);
+ impl_->Click(button_index, reply);
}
void ThunkNotificationDelegate::SettingsClick() {
@@ -72,12 +62,9 @@ HandleNotificationClickDelegate::HandleNotificationClickDelegate(
HandleNotificationClickDelegate::~HandleNotificationClickDelegate() {}
-void HandleNotificationClickDelegate::Click() {
- if (!callback_.is_null())
- callback_.Run(base::nullopt);
-}
-
-void HandleNotificationClickDelegate::ButtonClick(int button_index) {
+void HandleNotificationClickDelegate::Click(
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {
if (!callback_.is_null())
callback_.Run(button_index);
}
diff --git a/chromium/ui/message_center/public/cpp/notification_delegate.h b/chromium/ui/message_center/public/cpp/notification_delegate.h
index 8f5a5321969..1c2e62c4668 100644
--- a/chromium/ui/message_center/public/cpp/notification_delegate.h
+++ b/chromium/ui/message_center/public/cpp/notification_delegate.h
@@ -21,22 +21,19 @@ namespace message_center {
// Handles actions performed on a notification.
class MESSAGE_CENTER_PUBLIC_EXPORT NotificationObserver {
public:
- // To be called when the desktop notification is closed. If closed by a
- // user explicitly (as opposed to timeout/script), |by_user| should be true.
+ // Called when the desktop notification is closed. If closed by a user
+ // explicitly (as opposed to timeout/script), |by_user| should be true.
virtual void Close(bool by_user) {}
- // To be called when a desktop notification is clicked.
- virtual void Click() {}
+ // Called when a desktop notification is clicked. |button_index| is filled in
+ // if a button was clicked (as opposed to the body of the notification) while
+ // |reply| is filled in if there was an input field associated with the
+ // button.
+ virtual void Click(const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {}
- // To be called when the user clicks a button in a notification.
- virtual void ButtonClick(int button_index) {}
-
- // To be called when the user types a reply to a notification.
- virtual void ButtonClickWithReply(int button_index,
- const base::string16& reply) {}
-
- // To be called when the user clicks the settings button in a notification
- // which has a DELEGATE settings button action.
+ // Called when the user clicks the settings button in a notification which has
+ // a DELEGATE settings button action.
virtual void SettingsClick() {}
// Called when the user attempts to disable the notification.
@@ -58,8 +55,7 @@ class MESSAGE_CENTER_PUBLIC_EXPORT NotificationDelegate
// A pass-through which converts the RefCounted requirement to a WeakPtr
// requirement. This class replaces the need for individual delegates that pass
// through to an actual controller class, and which only exist because the
-// actual controller has a strong ownership model. TODO(estade): replace many
-// existing NotificationDelegate overrides with an instance of this class.
+// actual controller has a strong ownership model.
class MESSAGE_CENTER_PUBLIC_EXPORT ThunkNotificationDelegate
: public NotificationDelegate {
public:
@@ -67,10 +63,8 @@ class MESSAGE_CENTER_PUBLIC_EXPORT ThunkNotificationDelegate
// NotificationDelegate:
void Close(bool by_user) override;
- void Click() override;
- void ButtonClick(int button_index) override;
- void ButtonClickWithReply(int button_index,
- const base::string16& reply) override;
+ void Click(const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override;
void SettingsClick() override;
void DisableNotification() override;
@@ -102,8 +96,8 @@ class MESSAGE_CENTER_PUBLIC_EXPORT HandleNotificationClickDelegate
const base::RepeatingClosure& closure);
// NotificationDelegate overrides:
- void Click() override;
- void ButtonClick(int button_index) override;
+ void Click(const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override;
protected:
~HandleNotificationClickDelegate() override;
diff --git a/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc b/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc
index 09874d1ceeb..bd600a7ee64 100644
--- a/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc
+++ b/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc
@@ -37,7 +37,7 @@ TEST_F(NotificationDelegateTest, ClickDelegate) {
base::Bind(&NotificationDelegateTest::BodyClickCallback,
base::Unretained(this)));
- delegate->Click();
+ delegate->Click(base::nullopt, base::nullopt);
EXPECT_EQ(1, callback_count_);
}
@@ -45,7 +45,7 @@ TEST_F(NotificationDelegateTest, NullClickDelegate) {
auto delegate =
base::MakeRefCounted<HandleNotificationClickDelegate>(base::Closure());
- delegate->Click();
+ delegate->Click(base::nullopt, base::nullopt);
EXPECT_EQ(0, callback_count_);
}
@@ -54,11 +54,11 @@ TEST_F(NotificationDelegateTest, ButtonClickDelegate) {
base::Bind(&NotificationDelegateTest::ButtonClickCallback,
base::Unretained(this)));
- delegate->Click();
+ delegate->Click(base::nullopt, base::nullopt);
EXPECT_EQ(1, callback_count_);
EXPECT_EQ(base::nullopt, last_button_index_);
- delegate->ButtonClick(3);
+ delegate->Click(3, base::nullopt);
EXPECT_EQ(2, callback_count_);
EXPECT_EQ(3, *last_button_index_);
}
diff --git a/chromium/ui/message_center/public/mojo/BUILD.gn b/chromium/ui/message_center/public/mojo/BUILD.gn
index d6aaf8314fe..59d1d2bf31f 100644
--- a/chromium/ui/message_center/public/mojo/BUILD.gn
+++ b/chromium/ui/message_center/public/mojo/BUILD.gn
@@ -12,6 +12,7 @@ mojom("mojo") {
public_deps = [
"//mojo/common:common_custom_types",
+ "//mojo/public/mojom/base",
"//ui/gfx/image/mojo:interfaces",
"//url/mojom:url_mojom_gurl",
]
diff --git a/chromium/ui/message_center/public/mojo/notification.mojom b/chromium/ui/message_center/public/mojo/notification.mojom
index 1b1b4ba3cd2..823517c3a43 100644
--- a/chromium/ui/message_center/public/mojo/notification.mojom
+++ b/chromium/ui/message_center/public/mojo/notification.mojom
@@ -4,7 +4,7 @@
module message_center.mojom;
-import "mojo/common/time.mojom";
+import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/string16.mojom";
import "ui/gfx/image/mojo/image.mojom";
import "ui/message_center/public/mojo/notifier_id.mojom";
@@ -51,7 +51,7 @@ struct ButtonInfo {
struct RichNotificationData {
int32 priority;
bool never_time_out;
- mojo.common.mojom.Time timestamp;
+ mojo_base.mojom.Time timestamp;
// |context_message| intentionally omitted. See https://crbug.com/797084
gfx.mojom.ImageSkia? image;
gfx.mojom.ImageSkia? small_image;
@@ -60,7 +60,6 @@ struct RichNotificationData {
mojo_base.mojom.String16 progress_status;
array<ButtonInfo> buttons;
bool should_make_spoken_feedback_for_popup_updates;
- bool clickable;
bool pinned;
// |vibration_pattern| intentionally omitted
// |renotify| intentionally omitted
diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.cc b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
index 35b84fdf5e0..0a51cb6fa9d 100644
--- a/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
+++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc
@@ -4,8 +4,8 @@
#include "ui/message_center/public/mojo/notification_struct_traits.h"
-#include "mojo/common/time_struct_traits.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "ui/gfx/image/mojo/image_skia_struct_traits.h"
#include "ui/message_center/public/mojo/notifier_id_struct_traits.h"
#include "url/mojom/url_gurl_mojom_traits.h"
@@ -112,12 +112,6 @@ bool RichNotificationDataStructTraits::
}
// static
-bool RichNotificationDataStructTraits::clickable(
- const RichNotificationData& r) {
- return r.clickable;
-}
-
-// static
bool RichNotificationDataStructTraits::pinned(const RichNotificationData& r) {
return r.pinned;
}
@@ -171,7 +165,6 @@ bool RichNotificationDataStructTraits::Read(RichNotificationDataDataView data,
out->progress = data.progress();
out->should_make_spoken_feedback_for_popup_updates =
data.should_make_spoken_feedback_for_popup_updates();
- out->clickable = data.clickable();
out->pinned = data.pinned();
// Look up the vector icon by ID. This will only work if RegisterVectorIcon
@@ -179,8 +172,10 @@ bool RichNotificationDataStructTraits::Read(RichNotificationDataDataView data,
std::string icon_id;
if (data.ReadVectorSmallImageId(&icon_id) && !icon_id.empty()) {
out->vector_small_image = message_center::GetRegisteredVectorIcon(icon_id);
- if (!out->vector_small_image)
+ if (!out->vector_small_image) {
LOG(ERROR) << "Couldn't find icon: " + icon_id;
+ return false;
+ }
}
out->accent_color = data.accent_color();
diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.h b/chromium/ui/message_center/public/mojo/notification_struct_traits.h
index e97e4a6c504..4c35d5f716e 100644
--- a/chromium/ui/message_center/public/mojo/notification_struct_traits.h
+++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.h
@@ -175,7 +175,6 @@ struct StructTraits<message_center::mojom::RichNotificationDataDataView,
const message_center::RichNotificationData& r);
static bool should_make_spoken_feedback_for_popup_updates(
const message_center::RichNotificationData& r);
- static bool clickable(const message_center::RichNotificationData& r);
static bool pinned(const message_center::RichNotificationData& r);
static const base::string16& accessible_name(
const message_center::RichNotificationData& r);
diff --git a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
index d2b9f6b3e64..016424fedc8 100644
--- a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
+++ b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include "ui/message_center/public/mojo/notifier_id_struct_traits.h"
-
-#include "mojo/common/common_custom_types_struct_traits.h"
#include "url/mojom/url_gurl_mojom_traits.h"
namespace mojo {
diff --git a/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
index 59f0263524b..39e8dcae9c2 100644
--- a/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
@@ -49,7 +49,6 @@ class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
.should_make_spoken_feedback_for_popup_updates,
output.rich_notification_data()
.should_make_spoken_feedback_for_popup_updates);
- EXPECT_EQ(input.clickable(), output.clickable());
EXPECT_EQ(input.accessible_name(), output.accessible_name());
EXPECT_EQ(input.accent_color(), output.accent_color());
EXPECT_EQ(input.should_show_settings_button(),
@@ -97,7 +96,6 @@ TEST_F(StructTraitsTest, Notification) {
input.set_type(NotificationType::NOTIFICATION_TYPE_PROGRESS);
input.set_progress(50);
input.set_progress_status(base::ASCIIToUTF16("progress text"));
- input.set_clickable(!input.clickable());
input.set_image(gfx::test::CreateImage(48, 48));
input.set_small_image(gfx::test::CreateImage(16, 16));
input.set_accent_color(SK_ColorMAGENTA);
diff --git a/chromium/ui/message_center/ui_controller.cc b/chromium/ui/message_center/ui_controller.cc
index 997b24750f9..1572243177f 100644
--- a/chromium/ui/message_center/ui_controller.cc
+++ b/chromium/ui/message_center/ui_controller.cc
@@ -130,14 +130,10 @@ void UiController::OnNotificationUpdated(const std::string& notification_id) {
OnMessageCenterChanged();
}
-void UiController::OnNotificationClicked(const std::string& notification_id) {
- if (popups_visible_)
- OnMessageCenterChanged();
-}
-
-void UiController::OnNotificationButtonClicked(
+void UiController::OnNotificationClicked(
const std::string& notification_id,
- int button_index) {
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) {
if (popups_visible_)
OnMessageCenterChanged();
}
diff --git a/chromium/ui/message_center/ui_controller.h b/chromium/ui/message_center/ui_controller.h
index 582ad520d4e..5b489e06bae 100644
--- a/chromium/ui/message_center/ui_controller.h
+++ b/chromium/ui/message_center/ui_controller.h
@@ -60,9 +60,10 @@ class MESSAGE_CENTER_EXPORT UiController : public MessageCenterObserver {
void OnNotificationRemoved(const std::string& notification_id,
bool by_user) override;
void OnNotificationUpdated(const std::string& notification_id) override;
- void OnNotificationClicked(const std::string& notification_id) override;
- void OnNotificationButtonClicked(const std::string& notification_id,
- int button_index) override;
+ void OnNotificationClicked(
+ const std::string& notification_id,
+ const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override;
void OnNotificationSettingsClicked(bool handled) override;
void OnNotificationDisplayed(const std::string& notification_id,
const DisplaySource source) override;
diff --git a/chromium/ui/message_center/vector_icons/notification_close_button.1x.icon b/chromium/ui/message_center/vector_icons/notification_close_button.1x.icon
deleted file mode 100644
index 2bea75dea16..00000000000
--- a/chromium/ui/message_center/vector_icons/notification_close_button.1x.icon
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 12,
-MOVE_TO, 10.5f, 2.36f,
-LINE_TO, 9.64f, 1.5f,
-LINE_TO, 6, 5.14f,
-LINE_TO, 2.36f, 1.5f,
-LINE_TO, 1.5f, 2.36f,
-LINE_TO, 5.14f, 6,
-LINE_TO, 1.5f, 9.64f,
-LINE_TO, 2.36f, 10.5f,
-LINE_TO, 6, 6.86f,
-LINE_TO, 9.64f, 10.5f,
-LINE_TO, 10.5f, 9.64f,
-LINE_TO, 6.86f, 6,
-CLOSE,
-END
diff --git a/chromium/ui/message_center/vector_icons/notification_close_button.icon b/chromium/ui/message_center/vector_icons/notification_close_button.icon
index 5ce70e49153..ced7c26b683 100644
--- a/chromium/ui/message_center/vector_icons/notification_close_button.icon
+++ b/chromium/ui/message_center/vector_icons/notification_close_button.icon
@@ -15,5 +15,19 @@ LINE_TO, 12, 13.73f,
LINE_TO, 18.27f, 20,
LINE_TO, 20, 18.27f,
LINE_TO, 13.73f, 12,
-CLOSE,
-END
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 10.5f, 2.36f,
+LINE_TO, 9.64f, 1.5f,
+LINE_TO, 6, 5.14f,
+LINE_TO, 2.36f, 1.5f,
+LINE_TO, 1.5f, 2.36f,
+LINE_TO, 5.14f, 6,
+LINE_TO, 1.5f, 9.64f,
+LINE_TO, 2.36f, 10.5f,
+LINE_TO, 6, 6.86f,
+LINE_TO, 9.64f, 10.5f,
+LINE_TO, 10.5f, 9.64f,
+LINE_TO, 6.86f, 6,
+CLOSE
diff --git a/chromium/ui/message_center/vector_icons/notification_expand_less.icon b/chromium/ui/message_center/vector_icons/notification_expand_less.icon
index b30ee4211b5..d15fce2af57 100644
--- a/chromium/ui/message_center/vector_icons/notification_expand_less.icon
+++ b/chromium/ui/message_center/vector_icons/notification_expand_less.icon
@@ -9,5 +9,4 @@ LINE_TO, 13.33f, 13,
LINE_TO, 15, 11.31f,
R_LINE_TO, -7, -6.89f,
R_LINE_TO, -7, 6.89f,
-CLOSE,
-END
+CLOSE
diff --git a/chromium/ui/message_center/vector_icons/notification_expand_more.icon b/chromium/ui/message_center/vector_icons/notification_expand_more.icon
index b779f5f8e5c..155f6b58871 100644
--- a/chromium/ui/message_center/vector_icons/notification_expand_more.icon
+++ b/chromium/ui/message_center/vector_icons/notification_expand_more.icon
@@ -9,5 +9,4 @@ LINE_TO, 13.33f, 3,
LINE_TO, 15, 4.69f,
R_LINE_TO, -7, 6.89f,
R_LINE_TO, -7, -6.89f,
-CLOSE,
-END
+CLOSE
diff --git a/chromium/ui/message_center/vector_icons/notification_inline_reply.icon b/chromium/ui/message_center/vector_icons/notification_inline_reply.icon
index e12869934bf..abb71d49ff5 100644
--- a/chromium/ui/message_center/vector_icons/notification_inline_reply.icon
+++ b/chromium/ui/message_center/vector_icons/notification_inline_reply.icon
@@ -9,5 +9,4 @@ LINE_TO, 10.04f, 14,
LINE_TO, 10, 40.44f,
LINE_TO, 64.29f, 48,
LINE_TO, 10, 55.56f,
-CLOSE,
-END \ No newline at end of file
+CLOSE
diff --git a/chromium/ui/message_center/vector_icons/notification_settings_button.1x.icon b/chromium/ui/message_center/vector_icons/notification_settings_button.1x.icon
deleted file mode 100644
index d9996915b9b..00000000000
--- a/chromium/ui/message_center/vector_icons/notification_settings_button.1x.icon
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 12,
-MOVE_TO, 9.82f, 6.49f,
-CUBIC_TO, 9.84f, 6.33f, 9.85f, 6.17f, 9.85f, 6,
-CUBIC_TO, 9.85f, 5.84f, 9.84f, 5.67f, 9.82f, 5.51f,
-LINE_TO, 10.9f, 4.68f,
-CUBIC_TO, 11, 4.61f, 11.03f, 4.47f, 10.97f, 4.37f,
-LINE_TO, 9.94f, 2.63f,
-CUBIC_TO, 9.87f, 2.53f, 9.74f, 2.48f, 9.62f, 2.53f,
-LINE_TO, 8.34f, 3.03f,
-CUBIC_TO, 8.08f, 2.83f, 7.79f, 2.66f, 7.48f, 2.54f,
-LINE_TO, 7.28f, 1.21f,
-CUBIC_TO, 7.26f, 1.09f, 7.15f, 1, 7.03f, 1,
-LINE_TO, 4.97f, 1,
-CUBIC_TO, 4.84f, 1, 4.74f, 1.09f, 4.72f, 1.21f,
-LINE_TO, 4.52f, 2.54f,
-CUBIC_TO, 4.21f, 2.66f, 3.92f, 2.83f, 3.66f, 3.03f,
-LINE_TO, 2.38f, 2.53f,
-CUBIC_TO, 2.26f, 2.48f, 2.13f, 2.53f, 2.06f, 2.63f,
-LINE_TO, 1.03f, 4.37f,
-CUBIC_TO, 0.97f, 4.47f, 1, 4.61f, 1.1f, 4.68f,
-LINE_TO, 2.18f, 5.51f,
-CUBIC_TO, 2.16f, 5.67f, 2.14f, 5.84f, 2.14f, 6,
-CUBIC_TO, 2.14f, 6.17f, 2.16f, 6.33f, 2.18f, 6.49f,
-LINE_TO, 1.1f, 7.32f,
-CUBIC_TO, 1, 7.39f, 0.97f, 7.53f, 1.03f, 7.64f,
-LINE_TO, 2.06f, 9.37f,
-CUBIC_TO, 2.13f, 9.48f, 2.26f, 9.52f, 2.38f, 9.48f,
-LINE_TO, 3.66f, 8.97f,
-CUBIC_TO, 3.92f, 9.17f, 4.21f, 9.34f, 4.52f, 9.47f,
-LINE_TO, 4.72f, 10.79f,
-CUBIC_TO, 4.74f, 10.91f, 4.84f, 11, 4.97f, 11,
-LINE_TO, 7.03f, 11,
-CUBIC_TO, 7.15f, 11, 7.26f, 10.91f, 7.28f, 10.79f,
-LINE_TO, 7.47f, 9.47f,
-CUBIC_TO, 7.79f, 9.34f, 8.08f, 9.17f, 8.34f, 8.97f,
-LINE_TO, 9.62f, 9.48f,
-CUBIC_TO, 9.74f, 9.52f, 9.87f, 9.48f, 9.94f, 9.37f,
-LINE_TO, 10.96f, 7.64f,
-CUBIC_TO, 11.03f, 7.53f, 11, 7.39f, 10.9f, 7.32f,
-LINE_TO, 9.82f, 6.49f,
-LINE_TO, 9.82f, 6.49f,
-CLOSE,
-MOVE_TO, 6, 7.5f,
-CUBIC_TO, 5.17f, 7.5f, 4.5f, 6.83f, 4.5f, 6,
-CUBIC_TO, 4.5f, 5.17f, 5.17f, 4.5f, 6, 4.5f,
-CUBIC_TO, 6.83f, 4.5f, 7.5f, 5.17f, 7.5f, 6,
-CUBIC_TO, 7.5f, 6.83f, 6.83f, 7.5f, 6, 7.5f,
-LINE_TO, 6, 7.5f,
-CLOSE,
-END
diff --git a/chromium/ui/message_center/vector_icons/notification_settings_button.icon b/chromium/ui/message_center/vector_icons/notification_settings_button.icon
index ae7e26af6fa..3a0a1d9735a 100644
--- a/chromium/ui/message_center/vector_icons/notification_settings_button.icon
+++ b/chromium/ui/message_center/vector_icons/notification_settings_button.icon
@@ -50,5 +50,54 @@ CUBIC_TO, 9, 10.34f, 10.34f, 9, 12, 9,
CUBIC_TO, 13.66f, 9, 15, 10.34f, 15, 12,
CUBIC_TO, 15, 13.66f, 13.66f, 15, 12, 15,
LINE_TO, 12, 15,
+CLOSE
+
+CANVAS_DIMENSIONS, 12,
+MOVE_TO, 9.82f, 6.49f,
+CUBIC_TO, 9.84f, 6.33f, 9.85f, 6.17f, 9.85f, 6,
+CUBIC_TO, 9.85f, 5.84f, 9.84f, 5.67f, 9.82f, 5.51f,
+LINE_TO, 10.9f, 4.68f,
+CUBIC_TO, 11, 4.61f, 11.03f, 4.47f, 10.97f, 4.37f,
+LINE_TO, 9.94f, 2.63f,
+CUBIC_TO, 9.87f, 2.53f, 9.74f, 2.48f, 9.62f, 2.53f,
+LINE_TO, 8.34f, 3.03f,
+CUBIC_TO, 8.08f, 2.83f, 7.79f, 2.66f, 7.48f, 2.54f,
+LINE_TO, 7.28f, 1.21f,
+CUBIC_TO, 7.26f, 1.09f, 7.15f, 1, 7.03f, 1,
+LINE_TO, 4.97f, 1,
+CUBIC_TO, 4.84f, 1, 4.74f, 1.09f, 4.72f, 1.21f,
+LINE_TO, 4.52f, 2.54f,
+CUBIC_TO, 4.21f, 2.66f, 3.92f, 2.83f, 3.66f, 3.03f,
+LINE_TO, 2.38f, 2.53f,
+CUBIC_TO, 2.26f, 2.48f, 2.13f, 2.53f, 2.06f, 2.63f,
+LINE_TO, 1.03f, 4.37f,
+CUBIC_TO, 0.97f, 4.47f, 1, 4.61f, 1.1f, 4.68f,
+LINE_TO, 2.18f, 5.51f,
+CUBIC_TO, 2.16f, 5.67f, 2.14f, 5.84f, 2.14f, 6,
+CUBIC_TO, 2.14f, 6.17f, 2.16f, 6.33f, 2.18f, 6.49f,
+LINE_TO, 1.1f, 7.32f,
+CUBIC_TO, 1, 7.39f, 0.97f, 7.53f, 1.03f, 7.64f,
+LINE_TO, 2.06f, 9.37f,
+CUBIC_TO, 2.13f, 9.48f, 2.26f, 9.52f, 2.38f, 9.48f,
+LINE_TO, 3.66f, 8.97f,
+CUBIC_TO, 3.92f, 9.17f, 4.21f, 9.34f, 4.52f, 9.47f,
+LINE_TO, 4.72f, 10.79f,
+CUBIC_TO, 4.74f, 10.91f, 4.84f, 11, 4.97f, 11,
+LINE_TO, 7.03f, 11,
+CUBIC_TO, 7.15f, 11, 7.26f, 10.91f, 7.28f, 10.79f,
+LINE_TO, 7.47f, 9.47f,
+CUBIC_TO, 7.79f, 9.34f, 8.08f, 9.17f, 8.34f, 8.97f,
+LINE_TO, 9.62f, 9.48f,
+CUBIC_TO, 9.74f, 9.52f, 9.87f, 9.48f, 9.94f, 9.37f,
+LINE_TO, 10.96f, 7.64f,
+CUBIC_TO, 11.03f, 7.53f, 11, 7.39f, 10.9f, 7.32f,
+LINE_TO, 9.82f, 6.49f,
+LINE_TO, 9.82f, 6.49f,
CLOSE,
-END
+MOVE_TO, 6, 7.5f,
+CUBIC_TO, 5.17f, 7.5f, 4.5f, 6.83f, 4.5f, 6,
+CUBIC_TO, 4.5f, 5.17f, 5.17f, 4.5f, 6, 4.5f,
+CUBIC_TO, 6.83f, 4.5f, 7.5f, 5.17f, 7.5f, 6,
+CUBIC_TO, 7.5f, 6.83f, 6.83f, 7.5f, 6, 7.5f,
+LINE_TO, 6, 7.5f,
+CLOSE
diff --git a/chromium/ui/message_center/vector_icons/product.icon b/chromium/ui/message_center/vector_icons/product.icon
index 97f8448b152..7068cb20b97 100644
--- a/chromium/ui/message_center/vector_icons/product.icon
+++ b/chromium/ui/message_center/vector_icons/product.icon
@@ -32,5 +32,4 @@ R_CUBIC_TO, -7.73f, 0, -14, -6.27f, -14, -14,
R_CUBIC_TO, 0, -7.73f, 6.27f, -14, 14, -14,
R_CUBIC_TO, 7.73f, 0, 14, 6.27f, 14, 14,
R_CUBIC_TO, 0, 7.73f, -6.27f, 14, -14, 14,
-CLOSE,
-END
+CLOSE
diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc
index edd1bbdf3ad..e28f4563676 100644
--- a/chromium/ui/message_center/views/message_popup_collection.cc
+++ b/chromium/ui/message_center/views/message_popup_collection.cc
@@ -172,7 +172,8 @@ void MessagePopupCollection::UpdateWidgets() {
// Create top-level notification.
MessageView* view = MessageViewFactory::Create(notification, true);
observed_views_.Add(view);
- view->SetExpanded(true);
+ if (!view->IsManuallyExpandedOrCollapsed())
+ view->SetExpanded(view->IsAutoExpandingAllowed());
#if !defined(OS_CHROMEOS)
view->set_context_menu_controller(context_menu_controller_.get());
@@ -190,8 +191,14 @@ void MessagePopupCollection::UpdateWidgets() {
ToastContentsView* toast = new ToastContentsView(
notification.id(), alignment_delegate_, weak_factory_.GetWeakPtr());
+
+ const RichNotificationData& optional_fields =
+ notification.rich_notification_data();
+ bool a11y_feedback_for_updates =
+ optional_fields.should_make_spoken_feedback_for_popup_updates;
+
// There will be no contents already since this is a new ToastContentsView.
- toast->SetContents(view, /*a11y_feedback_for_updates=*/false);
+ toast->SetContents(view, a11y_feedback_for_updates);
toasts_.push_back(toast);
gfx::Size preferred_size = toast->GetPreferredSize();
@@ -343,8 +350,7 @@ void MessagePopupCollection::OnNotificationRemoved(
RemoveToast(*iter, /*mark_as_shown=*/true);
- if (by_user)
- RepositionWidgets();
+ DoUpdate();
}
void MessagePopupCollection::OnNotificationUpdated(
diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc
index 41912b341f7..7c8b678de4a 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/feature_list.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
@@ -17,6 +18,7 @@
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/features.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
+#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
@@ -94,7 +96,11 @@ MessageView::~MessageView() {}
void MessageView::UpdateWithNotification(const Notification& notification) {
pinned_ = notification.pinned();
- accessible_name_ = CreateAccessibleName(notification);
+ base::string16 new_accessible_name = CreateAccessibleName(notification);
+ if (new_accessible_name != accessible_name_) {
+ accessible_name_ = new_accessible_name;
+ NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
+ }
slide_out_controller_.set_enabled(!GetPinned());
}
@@ -124,6 +130,21 @@ void MessageView::SetIsNested() {
}
}
+bool MessageView::IsCloseButtonFocused() const {
+ auto* control_buttons_view = GetControlButtonsView();
+ return control_buttons_view ? control_buttons_view->IsCloseButtonFocused()
+ : false;
+}
+
+void MessageView::RequestFocusOnCloseButton() {
+ auto* control_buttons_view = GetControlButtonsView();
+ if (!control_buttons_view)
+ return;
+
+ control_buttons_view->RequestFocusOnCloseButton();
+ UpdateControlButtonsVisibility();
+}
+
void MessageView::SetExpanded(bool expanded) {
// Not implemented by default.
}
@@ -133,6 +154,11 @@ bool MessageView::IsExpanded() const {
return false;
}
+bool MessageView::IsAutoExpandingAllowed() const {
+ // Allowed by default.
+ return true;
+}
+
bool MessageView::IsManuallyExpandedOrCollapsed() const {
// Not implemented by default.
return false;
@@ -160,11 +186,18 @@ void MessageView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
}
bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
+ return true;
+}
+
+bool MessageView::OnMouseDragged(const ui::MouseEvent& event) {
+ return true;
+}
+
+void MessageView::OnMouseReleased(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
- return false;
+ return;
MessageCenter::Get()->ClickOnNotification(notification_id_);
- return true;
}
bool MessageView::OnKeyPressed(const ui::KeyEvent& event) {
@@ -271,8 +304,17 @@ ui::Layer* MessageView::GetSlideOutLayer() {
void MessageView::OnSlideChanged() {}
void MessageView::OnSlideOut() {
- MessageCenter::Get()->RemoveNotification(notification_id_,
- true /* by_user */);
+ // As a workaround for a MessagePopupCollection bug https://crbug.com/805208,
+ // pass false to by_user although it is triggered by user.
+ // TODO(tetsui): Rewrite MessagePopupCollection and remove this hack.
+ if (pinned_) {
+ // Also a workaround to not break notification pinning.
+ MessageCenter::Get()->MarkSinglePopupAsShown(
+ notification_id_, true /* mark_notification_as_read */);
+ } else {
+ MessageCenter::Get()->RemoveNotification(notification_id_,
+ true /* by_user */);
+ }
}
bool MessageView::GetPinned() const {
diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h
index 0cbbaf18602..74df97012b8 100644
--- a/chromium/ui/message_center/views/message_view.h
+++ b/chromium/ui/message_center/views/message_view.h
@@ -28,14 +28,17 @@ class ScrollView;
namespace message_center {
+namespace test {
+class MessagePopupCollectionTest;
+}
+
class Notification;
class NotificationControlButtonsView;
// An base class for a notification entry. Contains background and other
// elements shared by derived notification views.
-class MESSAGE_CENTER_EXPORT MessageView
- : public views::InkDropHostView,
- public views::SlideOutController::Delegate {
+class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
+ public SlideOutController::Delegate {
public:
static const char kViewClassName[];
@@ -55,13 +58,16 @@ class MESSAGE_CENTER_EXPORT MessageView
// Creates a shadow around the notification and changes slide-out behavior.
void SetIsNested();
+ bool IsCloseButtonFocused() const;
+ void RequestFocusOnCloseButton();
+
virtual NotificationControlButtonsView* GetControlButtonsView() const = 0;
- virtual bool IsCloseButtonFocused() const = 0;
- virtual void RequestFocusOnCloseButton() = 0;
virtual void UpdateControlButtonsVisibility() = 0;
+ virtual const char* GetMessageViewSubClassName() const = 0;
virtual void SetExpanded(bool expanded);
virtual bool IsExpanded() const;
+ virtual bool IsAutoExpandingAllowed() const;
virtual bool IsManuallyExpandedOrCollapsed() const;
virtual void SetManuallyExpandedOrCollapsed(bool value);
@@ -78,16 +84,20 @@ class MESSAGE_CENTER_EXPORT MessageView
// views::View
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
+ bool OnMouseDragged(const ui::MouseEvent& event) override;
+ void OnMouseReleased(const ui::MouseEvent& event) override;
bool OnKeyPressed(const ui::KeyEvent& event) override;
bool OnKeyReleased(const ui::KeyEvent& event) override;
void OnPaint(gfx::Canvas* canvas) override;
void OnFocus() override;
void OnBlur() override;
void Layout() override;
- const char* GetClassName() const override;
void OnGestureEvent(ui::GestureEvent* event) override;
+ // Subclasses of MessageView shouldn't use this method to distinguish classes.
+ // Instead, use GetMessageViewSubClassName().
+ const char* GetClassName() const final;
- // views::SlideOutController::Delegate
+ // message_center::SlideOutController::Delegate
ui::Layer* GetSlideOutLayer() override;
void OnSlideChanged() override;
void OnSlideOut() override;
@@ -113,6 +123,8 @@ class MESSAGE_CENTER_EXPORT MessageView
bool is_nested() const { return is_nested_; }
private:
+ friend class test::MessagePopupCollectionTest;
+
std::string notification_id_;
views::View* background_view_ = nullptr; // Owned by views hierarchy.
views::ScrollView* scroller_ = nullptr;
@@ -124,7 +136,7 @@ class MESSAGE_CENTER_EXPORT MessageView
std::unique_ptr<views::Painter> focus_painter_;
- views::SlideOutController slide_out_controller_;
+ message_center::SlideOutController slide_out_controller_;
// True if |this| is embedded in another view. Equivalent to |!top_level| in
// MessageViewFactory parlance.
diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc
index 731494c65f6..b9b83d8e7c3 100644
--- a/chromium/ui/message_center/views/notification_header_view.cc
+++ b/chromium/ui/message_center/views/notification_header_view.cc
@@ -333,6 +333,17 @@ void NotificationHeaderView::ClearOverflowIndicator() {
UpdateSummaryTextVisibility();
}
+void NotificationHeaderView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ Button::GetAccessibleNodeData(node_data);
+
+ node_data->SetName(app_name_view_->text());
+ node_data->SetDescription(summary_text_view_->text() +
+ base::ASCIIToUTF16(" ") + timestamp_view_->text());
+
+ if (is_expanded_)
+ node_data->AddState(ax::mojom::State::kExpanded);
+}
+
void NotificationHeaderView::SetTimestamp(base::Time past) {
timestamp_view_->SetText(FormatToRelativeTime(past));
has_timestamp_ = true;
@@ -361,6 +372,7 @@ void NotificationHeaderView::SetExpanded(bool expanded) {
expand_button_->SetTooltipText(l10n_util::GetStringUTF16(
expanded ? IDS_MESSAGE_CENTER_COLLAPSE_NOTIFICATION
: IDS_MESSAGE_CENTER_EXPAND_NOTIFICATION));
+ NotifyAccessibilityEvent(ax::mojom::Event::kStateChanged, true);
}
void NotificationHeaderView::SetAccentColor(SkColor color) {
diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h
index dd40f3f5ebf..b1f14665034 100644
--- a/chromium/ui/message_center/views/notification_header_view.h
+++ b/chromium/ui/message_center/views/notification_header_view.h
@@ -42,6 +42,9 @@ class NotificationHeaderView : public views::Button {
bool IsExpandButtonEnabled();
void SetSubpixelRenderingEnabled(bool enabled);
+ // views::View:
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
// Button override:
std::unique_ptr<views::InkDrop> CreateInkDrop() override;
diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc
index 7dc5d5d0346..01604e6e8e7 100644
--- a/chromium/ui/message_center/views/notification_view.cc
+++ b/chromium/ui/message_center/views/notification_view.cc
@@ -43,7 +43,6 @@
#include "ui/views/layout/fill_layout.h"
#include "ui/views/native_cursor.h"
#include "ui/views/painter.h"
-#include "ui/views/view_targeter.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
@@ -146,33 +145,7 @@ void NotificationItemView::SetVisible(bool visible) {
// NotificationView ////////////////////////////////////////////////////////////
-views::View* NotificationView::TargetForRect(views::View* root,
- const gfx::Rect& rect) {
- CHECK_EQ(root, this);
-
- // TODO(tdanderson): Modify this function to support rect-based event
- // targeting. Using the center point of |rect| preserves this function's
- // expected behavior for the time being.
- gfx::Point point = rect.CenterPoint();
-
- // Want to return this for underlying views, otherwise GetCursor is not
- // called. But buttons are exceptions, they'll have their own event handlings.
- std::vector<views::View*> buttons(action_buttons_.begin(),
- action_buttons_.end());
- if (control_buttons_view_->settings_button())
- buttons.push_back(control_buttons_view_->settings_button());
- if (control_buttons_view_->close_button())
- buttons.push_back(control_buttons_view_->close_button());
-
- for (size_t i = 0; i < buttons.size(); ++i) {
- gfx::Point point_in_child = point;
- ConvertPointToTarget(this, buttons[i], &point_in_child);
- if (buttons[i]->HitTestPoint(point_in_child))
- return buttons[i]->GetEventHandlerForPoint(point_in_child);
- }
-
- return root;
-}
+const char NotificationView::kMessageViewSubClassName[] = "NotificationView";
void NotificationView::CreateOrUpdateViews(const Notification& notification) {
CreateOrUpdateTitleView(notification);
@@ -187,7 +160,7 @@ void NotificationView::CreateOrUpdateViews(const Notification& notification) {
}
NotificationView::NotificationView(const Notification& notification)
- : MessageView(notification), clickable_(notification.clickable()) {
+ : MessageView(notification) {
// Create the top_view_, which collects into a vertical box all content
// at the top of the notification (to the right of the icon) except for the
// close button.
@@ -221,8 +194,6 @@ NotificationView::NotificationView(const Notification& notification)
AddChildView(small_image_view_.get());
UpdateControlButtonsVisibilityWithNotification(notification);
- SetEventTargeter(
- std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
set_notify_enter_exit_on_child(true);
}
@@ -336,12 +307,6 @@ void NotificationView::ScrollRectToVisible(const gfx::Rect& rect) {
views::View::ScrollRectToVisible(GetLocalBounds());
}
-gfx::NativeCursor NotificationView::GetCursor(const ui::MouseEvent& event) {
- return clickable_ ? views::GetNativeHandCursor()
- : views::View::GetCursor(event);
-}
-
-
void NotificationView::OnMouseEntered(const ui::MouseEvent& event) {
MessageView::OnMouseEntered(event);
UpdateControlButtonsVisibility();
@@ -380,14 +345,6 @@ void NotificationView::ButtonPressed(views::Button* sender,
NOTREACHED();
}
-bool NotificationView::IsCloseButtonFocused() const {
- return control_buttons_view_->IsCloseButtonFocused();
-}
-
-void NotificationView::RequestFocusOnCloseButton() {
- control_buttons_view_->RequestFocusOnCloseButton();
-}
-
void NotificationView::CreateOrUpdateTitleView(
const Notification& notification) {
if (notification.title().empty()) {
@@ -672,6 +629,10 @@ NotificationControlButtonsView* NotificationView::GetControlButtonsView()
return control_buttons_view_;
}
+const char* NotificationView::GetMessageViewSubClassName() const {
+ return kMessageViewSubClassName;
+}
+
int NotificationView::GetMessageLineLimit(int title_lines, int width) const {
// Image notifications require that the image must be kept flush against
// their icons, but we can allow more text if no image.
diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h
index f1f0e2fbdef..0f1f8ced86f 100644
--- a/chromium/ui/message_center/views/notification_view.h
+++ b/chromium/ui/message_center/views/notification_view.h
@@ -13,7 +13,6 @@
#include "ui/message_center/views/message_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
-#include "ui/views/view_targeter_delegate.h"
namespace views {
class ImageView;
@@ -31,11 +30,11 @@ class ProportionalImageView;
// list) except the custom notification. Future notification types may be
// handled by other classes, in which case instances of those classes would be
// returned by the Create() factory method below.
-class MESSAGE_CENTER_EXPORT NotificationView
- : public MessageView,
- public views::ButtonListener,
- public views::ViewTargeterDelegate {
+class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
+ public views::ButtonListener {
public:
+ static const char kMessageViewSubClassName[];
+
explicit NotificationView(const Notification& notification);
~NotificationView() override;
@@ -45,17 +44,15 @@ class MESSAGE_CENTER_EXPORT NotificationView
void Layout() override;
void OnFocus() override;
void ScrollRectToVisible(const gfx::Rect& rect) override;
- gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
// Overridden from MessageView:
void UpdateWithNotification(const Notification& notification) override;
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
- bool IsCloseButtonFocused() const override;
- void RequestFocusOnCloseButton() override;
void UpdateControlButtonsVisibility() override;
NotificationControlButtonsView* GetControlButtonsView() const override;
+ const char* GetMessageViewSubClassName() const final;
private:
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, CreateOrUpdateTest);
@@ -71,9 +68,6 @@ class MESSAGE_CENTER_EXPORT NotificationView
friend class NotificationViewTest;
- // views::ViewTargeterDelegate:
- views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
-
void CreateOrUpdateViews(const Notification& notification);
void CreateOrUpdateTitleView(const Notification& notification);
@@ -101,9 +95,6 @@ class MESSAGE_CENTER_EXPORT NotificationView
// Shrink the topmost label not to be covered by the control button.
void ShrinkTopmostLabel();
- // Describes whether the view should display a hand pointer or not.
- bool clickable_;
-
// Weak references to NotificationView descendants owned by their parents.
views::View* top_view_ = nullptr;
BoundedLabel* title_view_ = nullptr;
diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc
index eaf1c4852b6..8d26e265a09 100644
--- a/chromium/ui/message_center/views/notification_view_md.cc
+++ b/chromium/ui/message_center/views/notification_view_md.cc
@@ -12,6 +12,8 @@
#include "components/url_formatter/elide_url.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/size.h"
@@ -42,7 +44,6 @@
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/native_cursor.h"
-#include "ui/views/view_targeter.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -169,6 +170,10 @@ class ClickActivator : public ui::EventHandler {
} // anonymous namespace
+// static
+const char NotificationViewMD::kMessageViewSubClassName[] =
+ "NotificationViewMD";
+
// ItemView ////////////////////////////////////////////////////////////////////
ItemView::ItemView(const NotificationItem& item) {
@@ -533,44 +538,6 @@ class InlineSettingsRadioButton : public views::RadioButton {
// NotificationViewMD
// ////////////////////////////////////////////////////////////
-views::View* NotificationViewMD::TargetForRect(views::View* root,
- const gfx::Rect& rect) {
- CHECK_EQ(root, this);
-
- // TODO(tetsui): Modify this function to support rect-based event
- // targeting. Using the center point of |rect| preserves this function's
- // expected behavior for the time being.
- gfx::Point point = rect.CenterPoint();
-
- // Want to return this for underlying views, otherwise GetCursor is not
- // called. But buttons are exceptions, they'll have their own event handlings.
- std::vector<views::View*> buttons;
- if (header_row_->expand_button())
- buttons.push_back(header_row_->expand_button());
- buttons.push_back(header_row_);
-
- if (action_buttons_row_->visible()) {
- buttons.insert(buttons.end(), action_buttons_.begin(),
- action_buttons_.end());
- }
- if (inline_reply_->visible())
- buttons.push_back(inline_reply_);
- if (settings_row_) {
- buttons.push_back(block_all_button_);
- buttons.push_back(dont_block_button_);
- buttons.push_back(settings_done_button_);
- }
-
- for (size_t i = 0; i < buttons.size(); ++i) {
- gfx::Point point_in_child = point;
- ConvertPointToTarget(this, buttons[i], &point_in_child);
- if (buttons[i]->HitTestPoint(point_in_child))
- return buttons[i]->GetEventHandlerForPoint(point_in_child);
- }
-
- return root;
-}
-
void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) {
CreateOrUpdateContextTitleView(notification);
CreateOrUpdateTitleView(notification);
@@ -591,8 +558,7 @@ void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) {
NotificationViewMD::NotificationViewMD(const Notification& notification)
: MessageView(notification),
- ink_drop_container_(new views::InkDropContainerView()),
- clickable_(notification.clickable()) {
+ ink_drop_container_(new views::InkDropContainerView()) {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), 0));
@@ -657,8 +623,6 @@ NotificationViewMD::NotificationViewMD(const Notification& notification)
CreateOrUpdateViews(notification);
UpdateControlButtonsVisibilityWithNotification(notification);
- SetEventTargeter(
- std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
set_notify_enter_exit_on_child(true);
click_activator_ = std::make_unique<ClickActivator>(this);
@@ -721,30 +685,28 @@ void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) {
views::View::ScrollRectToVisible(GetLocalBounds());
}
-gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) {
- // Do not change the cursor on a notification that isn't clickable.
- if (!clickable_)
- return views::View::GetCursor(event);
-
- // Do not change the cursor on the actions row.
- if (expanded_) {
- DCHECK(actions_row_);
- gfx::Point point_in_child = event.location();
- ConvertPointToTarget(this, actions_row_, &point_in_child);
- if (actions_row_->HitTestPoint(point_in_child))
- return views::View::GetCursor(event);
- }
-
- // Do not change the cursor when inline settings is shown.
- if (settings_row_ && settings_row_->visible())
- return views::View::GetCursor(event);
+bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) {
+ last_mouse_pressed_timestamp_ = base::TimeTicks(event.time_stamp());
+ return true;
+}
- return views::GetNativeHandCursor();
+bool NotificationViewMD::OnMouseDragged(const ui::MouseEvent& event) {
+ return true;
}
-bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) {
+void NotificationViewMD::OnMouseReleased(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
- return false;
+ return;
+
+ // The mouse has been clicked for a long time.
+ if (ui::EventTimeStampToSeconds(event.time_stamp()) -
+ ui::EventTimeStampToSeconds(last_mouse_pressed_timestamp_) >
+ ui::GetGestureProviderConfig(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM)
+ .gesture_detector_config.longpress_timeout.InSecondsF()) {
+ ToggleInlineSettings(event);
+ return;
+ }
// Ignore click of actions row outside action buttons.
if (expanded_) {
@@ -752,14 +714,14 @@ bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) {
gfx::Point point_in_child = event.location();
ConvertPointToTarget(this, actions_row_, &point_in_child);
if (actions_row_->HitTestPoint(point_in_child))
- return true;
+ return;
}
// Ignore clicks of outside region when inline settings is shown.
if (settings_row_ && settings_row_->visible())
- return true;
+ return;
- return MessageView::OnMousePressed(event);
+ MessageView::OnMouseReleased(event);
}
void NotificationViewMD::OnMouseEvent(ui::MouseEvent* event) {
@@ -776,6 +738,14 @@ void NotificationViewMD::OnMouseEvent(ui::MouseEvent* event) {
View::OnMouseEvent(event);
}
+void NotificationViewMD::OnGestureEvent(ui::GestureEvent* event) {
+ if (event->type() == ui::ET_GESTURE_LONG_TAP) {
+ ToggleInlineSettings(*event);
+ return;
+ }
+ MessageView::OnGestureEvent(event);
+}
+
void NotificationViewMD::UpdateWithNotification(
const Notification& notification) {
MessageView::UpdateWithNotification(notification);
@@ -848,14 +818,6 @@ void NotificationViewMD::OnNotificationInputSubmit(size_t index,
index, text);
}
-bool NotificationViewMD::IsCloseButtonFocused() const {
- return control_buttons_view_->IsCloseButtonFocused();
-}
-
-void NotificationViewMD::RequestFocusOnCloseButton() {
- control_buttons_view_->RequestFocusOnCloseButton();
-}
-
void NotificationViewMD::CreateOrUpdateContextTitleView(
const Notification& notification) {
header_row_->SetAccentColor(notification.accent_color() == SK_ColorTRANSPARENT
@@ -1274,7 +1236,8 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) {
}
void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
- DCHECK(settings_row_);
+ if (!settings_row_)
+ return;
bool inline_settings_visible = !settings_row_->visible();
@@ -1303,9 +1266,10 @@ void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
// among NotificationView and ArcNotificationView.
void NotificationViewMD::UpdateControlButtonsVisibility() {
const bool target_visibility =
- AlwaysShowControlButtons() || IsMouseHovered() ||
- control_buttons_view_->IsCloseButtonFocused() ||
- control_buttons_view_->IsSettingsButtonFocused();
+ (AlwaysShowControlButtons() || IsMouseHovered() ||
+ control_buttons_view_->IsCloseButtonFocused() ||
+ control_buttons_view_->IsSettingsButtonFocused()) &&
+ !GetPinned();
control_buttons_view_->SetVisible(target_visibility);
}
@@ -1344,13 +1308,17 @@ void NotificationViewMD::OnSettingsButtonPressed(const ui::Event& event) {
MessageView::OnSettingsButtonPressed(event);
}
+const char* NotificationViewMD::GetMessageViewSubClassName() const {
+ return kMessageViewSubClassName;
+}
+
void NotificationViewMD::Activate() {
GetWidget()->widget_delegate()->set_can_activate(true);
GetWidget()->Activate();
}
void NotificationViewMD::AddBackgroundAnimation(const ui::Event& event) {
- SetInkDropMode(InkDropMode::ON);
+ SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
// In case the animation is triggered from keyboard operation.
if (!event.IsLocatedEvent()) {
AnimateInkDrop(views::InkDropState::ACTION_PENDING, nullptr);
diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h
index d9ed79d902b..d4404224f49 100644
--- a/chromium/ui/message_center/views/notification_view_md.h
+++ b/chromium/ui/message_center/views/notification_view_md.h
@@ -10,6 +10,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "base/time/time.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/views/message_view.h"
#include "ui/views/animation/ink_drop_observer.h"
@@ -18,7 +19,6 @@
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/view_targeter_delegate.h"
namespace views {
class ImageButton;
@@ -218,9 +218,10 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
: public MessageView,
public views::InkDropObserver,
public NotificationInputDelegate,
- public views::ButtonListener,
- public views::ViewTargeterDelegate {
+ public views::ButtonListener {
public:
+ static const char kMessageViewSubClassName[];
+
explicit NotificationViewMD(const Notification& notification);
~NotificationViewMD() override;
@@ -233,9 +234,11 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
void Layout() override;
void OnFocus() override;
void ScrollRectToVisible(const gfx::Rect& rect) override;
- gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
+ bool OnMouseDragged(const ui::MouseEvent& event) override;
+ void OnMouseReleased(const ui::MouseEvent& event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
// Overridden from views::InkDropHostView:
void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
@@ -246,16 +249,14 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
// Overridden from MessageView:
void UpdateWithNotification(const Notification& notification) override;
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
- bool IsCloseButtonFocused() const override;
- void RequestFocusOnCloseButton() override;
void UpdateControlButtonsVisibility() override;
NotificationControlButtonsView* GetControlButtonsView() const override;
bool IsExpanded() const override;
void SetExpanded(bool expanded) override;
bool IsManuallyExpandedOrCollapsed() const override;
void SetManuallyExpandedOrCollapsed(bool value) override;
-
void OnSettingsButtonPressed(const ui::Event& event) override;
+ const char* GetMessageViewSubClassName() const final;
// views::InkDropObserver:
void InkDropAnimationStarted() override;
@@ -265,9 +266,6 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
void OnNotificationInputSubmit(size_t index,
const base::string16& text) override;
- // views::ViewTargeterDelegate:
- views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
-
private:
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, CreateOrUpdateTest);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing);
@@ -357,6 +355,8 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
std::unique_ptr<ui::EventHandler> click_activator_;
+ base::TimeTicks last_mouse_pressed_timestamp_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationViewMD);
};
diff --git a/chromium/ui/message_center/views/notification_view_md_unittest.cc b/chromium/ui/message_center/views/notification_view_md_unittest.cc
index f8574e2975f..ae5a86196de 100644
--- a/chromium/ui/message_center/views/notification_view_md_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc
@@ -37,26 +37,23 @@ class NotificationTestDelegate : public NotificationDelegate {
public:
NotificationTestDelegate() = default;
- void ButtonClick(int button_index) override {
- if (!expecting_button_click_)
- ADD_FAILURE() << "ClickOnNotificationButton should not be invoked.";
- clicked_button_index_ = button_index;
- }
-
- void ButtonClickWithReply(int button_index,
- const base::string16& reply) override {
- if (!expecting_reply_submission_) {
- ADD_FAILURE()
- << "ClickOnNotificationButtonWithReply should not be invoked.";
- }
-
- clicked_button_index_ = button_index;
- submitted_reply_string_ = reply;
+ void Click(const base::Optional<int>& button_index,
+ const base::Optional<base::string16>& reply) override {
+ if (!button_index)
+ return;
+
+ if (!reply && !expecting_button_click_)
+ ADD_FAILURE() << "Click should not be invoked with a button index.";
+ if (reply && !expecting_reply_submission_)
+ ADD_FAILURE() << "Click should not be invoked with a reply.";
+
+ clicked_button_index_ = *button_index;
+ submitted_reply_string_ = reply.value_or(base::string16());
}
void Reset() {
clicked_button_index_ = -1;
- submitted_reply_string_ = base::EmptyString16();
+ submitted_reply_string_.clear();
}
void DisableNotification() override { disable_notification_called_ = true; }
@@ -791,7 +788,7 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
EXPECT_FALSE(notification_view()->settings_row_->visible());
gfx::Point settings_cursor_location(1, 1);
views::View::ConvertPointToScreen(
- notification_view()->control_buttons_view_.get()->settings_button(),
+ notification_view()->control_buttons_view_->settings_button(),
&settings_cursor_location);
ui::test::EventGenerator generator(widget()->GetNativeWindow());
generator.MoveMouseTo(settings_cursor_location);
diff --git a/chromium/ui/message_center/views/slide_out_controller.cc b/chromium/ui/message_center/views/slide_out_controller.cc
index efcf8e027d1..6a863de1b87 100644
--- a/chromium/ui/message_center/views/slide_out_controller.cc
+++ b/chromium/ui/message_center/views/slide_out_controller.cc
@@ -8,7 +8,7 @@
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/transform.h"
-namespace views {
+namespace message_center {
SlideOutController::SlideOutController(ui::EventTarget* target,
Delegate* delegate)
@@ -108,4 +108,4 @@ void SlideOutController::OnImplicitAnimationsCompleted() {
delegate_->OnSlideOut();
}
-} // namespace views
+} // namespace message_center
diff --git a/chromium/ui/message_center/views/slide_out_controller.h b/chromium/ui/message_center/views/slide_out_controller.h
index 5b01df2d98e..c3f134eb270 100644
--- a/chromium/ui/message_center/views/slide_out_controller.h
+++ b/chromium/ui/message_center/views/slide_out_controller.h
@@ -8,15 +8,16 @@
#include "base/macros.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/events/scoped_target_handler.h"
+#include "ui/message_center/message_center_export.h"
#include "ui/views/view.h"
-#include "ui/views/views_export.h"
-namespace views {
+namespace message_center {
// This class contains logic to control sliding out of a layer in response to
// swipes, i.e. gesture scroll events.
-class SlideOutController : public ui::EventHandler,
- public ui::ImplicitAnimationObserver {
+class MESSAGE_CENTER_EXPORT SlideOutController
+ : public ui::EventHandler,
+ public ui::ImplicitAnimationObserver {
public:
class Delegate {
public:
@@ -59,6 +60,6 @@ class SlideOutController : public ui::EventHandler,
DISALLOW_COPY_AND_ASSIGN(SlideOutController);
};
-} // namespace views
+} // namespace message_center
#endif // UI_MESSAGE_CENTER_VIEWS_SLIDE_OUT_CONTROLLER_H_
diff --git a/chromium/ui/message_center/views/toast_contents_view.cc b/chromium/ui/message_center/views/toast_contents_view.cc
index 285ca0b30a2..23c84cf6d59 100644
--- a/chromium/ui/message_center/views/toast_contents_view.cc
+++ b/chromium/ui/message_center/views/toast_contents_view.cc
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
@@ -84,17 +85,11 @@ ToastContentsView::~ToastContentsView() {
void ToastContentsView::SetContents(MessageView* view,
bool a11y_feedback_for_updates) {
message_view_ = view;
- bool already_has_contents = child_count() > 0;
RemoveAllChildViews(true);
AddChildView(view);
UpdatePreferredSize();
-
- // If it has the contents already, this invocation means an update of the
- // popup toast, and the new contents should be read through a11y feature.
- // The notification type should be ALERT, otherwise the accessibility message
- // won't be read for this view which returns ROLE_WINDOW.
- if (already_has_contents && a11y_feedback_for_updates)
- NotifyAccessibilityEvent(ax::mojom::Event::kAlert, false);
+ if (a11y_feedback_for_updates)
+ NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
}
void ToastContentsView::UpdateContents(const Notification& notification,
@@ -104,7 +99,7 @@ void ToastContentsView::UpdateContents(const Notification& notification,
message_view->UpdateWithNotification(notification);
UpdatePreferredSize();
if (a11y_feedback_for_updates)
- NotifyAccessibilityEvent(ax::mojom::Event::kAlert, false);
+ NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
}
void ToastContentsView::RevealWithAnimation(gfx::Point origin) {
@@ -316,7 +311,7 @@ void ToastContentsView::UpdatePreferredSize() {
void ToastContentsView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (child_count() > 0)
child_at(0)->GetAccessibleNodeData(node_data);
- node_data->role = ax::mojom::Role::kWindow;
+ node_data->role = ax::mojom::Role::kAlertDialog;
}
const char* ToastContentsView::GetClassName() const {
diff --git a/chromium/ui/native_theme/common_theme.cc b/chromium/ui/native_theme/common_theme.cc
index 259f4f7cefd..33d7e8a5cec 100644
--- a/chromium/ui/native_theme/common_theme.cc
+++ b/chromium/ui/native_theme/common_theme.cc
@@ -5,7 +5,6 @@
#include "ui/native_theme/common_theme.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
@@ -97,6 +96,8 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
static const SkColor kMenuBorderColor = SkColorSetRGB(0xBA, 0xBA, 0xBA);
static const SkColor kMenuSeparatorColor = SkColorSetRGB(0xE9, 0xE9, 0xE9);
static const SkColor kEnabledMenuItemForegroundColor = SK_ColorBLACK;
+ static const SkColor kMenuItemMinorTextColor =
+ SkColorSetA(SK_ColorBLACK, 0x89);
// Separator:
static const SkColor kSeparatorColor = SkColorSetRGB(0xE9, 0xE9, 0xE9);
// Link:
@@ -200,9 +201,8 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
return kEnabledMenuItemForegroundColor;
case NativeTheme::kColorId_DisabledMenuItemForegroundColor:
return kDisabledTextColor;
- case NativeTheme::kColorId_MenuItemSubtitleColor:
- return base_theme->GetSystemColor(
- NativeTheme::kColorId_DisabledMenuItemForegroundColor);
+ case NativeTheme::kColorId_MenuItemMinorTextColor:
+ return kMenuItemMinorTextColor;
// Label
case NativeTheme::kColorId_LabelEnabledColor:
diff --git a/chromium/ui/native_theme/native_theme.h b/chromium/ui/native_theme/native_theme.h
index 01272180372..d926149c781 100644
--- a/chromium/ui/native_theme/native_theme.h
+++ b/chromium/ui/native_theme/native_theme.h
@@ -315,7 +315,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_DisabledMenuItemForegroundColor,
kColorId_SelectedMenuItemForegroundColor,
kColorId_FocusedMenuItemBackgroundColor,
- kColorId_MenuItemSubtitleColor,
+ kColorId_MenuItemMinorTextColor,
kColorId_MenuSeparatorColor,
kColorId_MenuBackgroundColor,
kColorId_MenuBorderColor,
diff --git a/chromium/ui/native_theme/native_theme_dark_aura.cc b/chromium/ui/native_theme/native_theme_dark_aura.cc
index 079b88cec6c..655b4879669 100644
--- a/chromium/ui/native_theme/native_theme_dark_aura.cc
+++ b/chromium/ui/native_theme/native_theme_dark_aura.cc
@@ -112,7 +112,7 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
case kColorId_DisabledMenuItemForegroundColor:
case kColorId_SelectedMenuItemForegroundColor:
case kColorId_FocusedMenuItemBackgroundColor:
- case kColorId_MenuItemSubtitleColor:
+ case kColorId_MenuItemMinorTextColor:
case kColorId_MenuSeparatorColor:
case kColorId_MenuBackgroundColor:
case kColorId_MenuBorderColor:
diff --git a/chromium/ui/native_theme/native_theme_mac.mm b/chromium/ui/native_theme/native_theme_mac.mm
index 758320fe283..84a2cd18a67 100644
--- a/chromium/ui/native_theme/native_theme_mac.mm
+++ b/chromium/ui/native_theme/native_theme_mac.mm
@@ -24,20 +24,10 @@
namespace {
-// Values calculated by reading pixels and solving simultaneous equations
-// derived from "A over B" alpha compositing. Steps: Sample the semi-transparent
-// pixel over two backgrounds; P1, P2 over backgrounds B1, B2. Use the color
-// value between 0.0 and 1.0 (i.e. divide by 255.0). Then,
-// alpha = (P2 - P1 + B1 - B2) / (B1 - B2)
-// color = (P1 - B1 + alpha * B1) / alpha.
-const SkColor kMenuPopupBackgroundColor = SkColorSetARGB(245, 255, 255, 255);
-const SkColor kMenuSeparatorColor = SkColorSetARGB(255, 217, 217, 217);
+const SkColor kMenuPopupBackgroundColor = SK_ColorWHITE;
+const SkColor kMenuSeparatorColor = SkColorSetA(SK_ColorBLACK, 38);
const SkColor kMenuBorderColor = SkColorSetARGB(60, 0, 0, 0);
-const SkColor kMenuPopupBackgroundColorMavericks =
- SkColorSetARGB(255, 255, 255, 255);
-const SkColor kMenuSeparatorColorMavericks = SkColorSetARGB(243, 228, 228, 228);
-
// Hardcoded color used for some existing dialogs in Chrome's Cocoa UI.
const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251);
@@ -139,14 +129,22 @@ SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
case kColorId_DisabledMenuItemForegroundColor:
return NSSystemColorToSkColor([NSColor disabledControlTextColor]);
case kColorId_SelectedMenuItemForegroundColor:
- return NSSystemColorToSkColor([NSColor selectedMenuItemTextColor]);
+ return SK_ColorBLACK;
case kColorId_FocusedMenuItemBackgroundColor:
- return NSSystemColorToSkColor([NSColor selectedMenuItemColor]);
+ // It's necessary to use a different alpha for Aqua mode vs Graphite mode,
+ // because the black used as the graphite base shows up well even at low
+ // alphas, but the blue used for Aqua needs a bit more alpha to show up
+ // properly. At the same alpha as the graphite uses, it's difficult to
+ // pick out clearly and looks somewhat like faint lilac instead of blue.
+ return ([NSColor currentControlTint] == NSGraphiteControlTint)
+ ? SkColorSetA(SK_ColorBLACK, 21)
+ : SkColorSetA(
+ NSSystemColorToSkColor([NSColor selectedMenuItemColor]),
+ 45);
case kColorId_MenuBackgroundColor:
return kMenuPopupBackgroundColor;
case kColorId_MenuSeparatorColor:
- return base::mac::IsOS10_9() ? kMenuSeparatorColorMavericks
- : kMenuSeparatorColor;
+ return kMenuSeparatorColor;
case kColorId_MenuBorderColor:
return kMenuBorderColor;
@@ -255,10 +253,7 @@ void NativeThemeMac::PaintMenuPopupBackground(
const MenuBackgroundExtraParams& menu_background) const {
cc::PaintFlags flags;
flags.setAntiAlias(true);
- if (base::mac::IsOS10_9())
- flags.setColor(kMenuPopupBackgroundColorMavericks);
- else
- flags.setColor(kMenuPopupBackgroundColor);
+ flags.setColor(kMenuPopupBackgroundColor);
const SkScalar radius = SkIntToScalar(menu_background.corner_radius);
SkRect rect = gfx::RectToSkRect(gfx::Rect(size));
canvas->drawRoundRect(rect, radius, radius, flags);
diff --git a/chromium/ui/ozone/common/egl_util.cc b/chromium/ui/ozone/common/egl_util.cc
index 9a40d1db001..86636c3f94b 100644
--- a/chromium/ui/ozone/common/egl_util.cc
+++ b/chromium/ui/ozone/common/egl_util.cc
@@ -14,12 +14,16 @@
namespace ui {
namespace {
-const char kDefaultEglSoname[] = "libEGL.so.1";
-const char kDefaultGlesSoname[] = "libGLESv2.so.2";
+const base::FilePath::CharType kDefaultEglSoname[] =
+ FILE_PATH_LITERAL("libEGL.so.1");
+const base::FilePath::CharType kDefaultGlesSoname[] =
+ FILE_PATH_LITERAL("libGLESv2.so.2");
#if BUILDFLAG(ENABLE_SWIFTSHADER)
-const char kGLESv2SwiftShaderLibraryName[] = "libGLESv2.so";
-const char kEGLSwiftShaderLibraryName[] = "libEGL.so";
+const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] =
+ FILE_PATH_LITERAL("libGLESv2.so");
+const base::FilePath::CharType kEGLSwiftShaderLibraryName[] =
+ FILE_PATH_LITERAL("libEGL.so");
#endif
bool LoadEGLGLES2Bindings(const base::FilePath& egl_library_path,
@@ -69,7 +73,7 @@ bool LoadDefaultEGLGLES2Bindings(gl::GLImplementation implementation) {
base::FilePath module_path;
if (!PathService::Get(base::DIR_MODULE, &module_path))
return false;
- module_path = module_path.Append("swiftshader/");
+ module_path = module_path.Append(FILE_PATH_LITERAL("swiftshader/"));
glesv2_path = module_path.Append(kGLESv2SwiftShaderLibraryName);
egl_path = module_path.Append(kEGLSwiftShaderLibraryName);
diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h
index 0c5ca179b9a..06065107640 100644
--- a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h
+++ b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -53,7 +53,8 @@ struct DisplaySnapshot_Params {
DisplayMode_Params current_mode;
bool has_native_mode = false;
DisplayMode_Params native_mode;
- int64_t product_id = 0;
+ int64_t product_code = 0;
+ int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
gfx::Size maximum_cursor_size;
};
diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h b/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h
index 6db409c8df7..d472f0830f1 100644
--- a/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h
+++ b/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h
@@ -4,6 +4,7 @@
// Multiply-included message file, hence no include guard here, but see below
// for a much smaller-than-usual include guard section.
+// no-include-guard-because-multiply-included
#include <stdint.h>
@@ -62,7 +63,8 @@ IPC_STRUCT_TRAITS_BEGIN(ui::DisplaySnapshot_Params)
IPC_STRUCT_TRAITS_MEMBER(current_mode)
IPC_STRUCT_TRAITS_MEMBER(has_native_mode)
IPC_STRUCT_TRAITS_MEMBER(native_mode)
- IPC_STRUCT_TRAITS_MEMBER(product_id)
+ IPC_STRUCT_TRAITS_MEMBER(product_code)
+ IPC_STRUCT_TRAITS_MEMBER(year_of_manufacture)
IPC_STRUCT_TRAITS_MEMBER(maximum_cursor_size)
IPC_STRUCT_TRAITS_END()
diff --git a/chromium/ui/ozone/demo/BUILD.gn b/chromium/ui/ozone/demo/BUILD.gn
index 8a01fb9b10e..71447419f9f 100644
--- a/chromium/ui/ozone/demo/BUILD.gn
+++ b/chromium/ui/ozone/demo/BUILD.gn
@@ -10,16 +10,22 @@ group("demo") {
executable("ozone_demo") {
sources = [
+ "demo_window.cc",
+ "demo_window.h",
"ozone_demo.cc",
"renderer.h",
"renderer_base.cc",
"renderer_base.h",
+ "renderer_factory.cc",
+ "renderer_factory.h",
"skia_renderer.cc",
"skia_renderer.h",
"software_renderer.cc",
"software_renderer.h",
"surfaceless_skia_renderer.cc",
"surfaceless_skia_renderer.h",
+ "window_manager.cc",
+ "window_manager.h",
]
deps = [
diff --git a/chromium/ui/ozone/demo/demo_window.cc b/chromium/ui/ozone/demo/demo_window.cc
new file mode 100644
index 00000000000..f641537e0f3
--- /dev/null
+++ b/chromium/ui/ozone/demo/demo_window.cc
@@ -0,0 +1,90 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/demo/demo_window.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/ozone/demo/renderer.h"
+#include "ui/ozone/demo/renderer_factory.h"
+#include "ui/ozone/demo/window_manager.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+DemoWindow::DemoWindow(WindowManager* window_manager,
+ RendererFactory* renderer_factory,
+ const gfx::Rect& bounds)
+ : window_manager_(window_manager),
+ renderer_factory_(renderer_factory),
+ weak_ptr_factory_(this) {
+ platform_window_ =
+ OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+ platform_window_->Show();
+}
+
+DemoWindow::~DemoWindow() {}
+
+gfx::AcceleratedWidget DemoWindow::GetAcceleratedWidget() {
+ // TODO(spang): We should start rendering asynchronously.
+ DCHECK_NE(widget_, gfx::kNullAcceleratedWidget)
+ << "Widget not available synchronously";
+ return widget_;
+}
+
+gfx::Size DemoWindow::GetSize() {
+ return platform_window_->GetBounds().size();
+}
+
+void DemoWindow::Start() {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DemoWindow::StartOnGpu, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DemoWindow::Quit() {
+ window_manager_->Quit();
+}
+
+void DemoWindow::OnBoundsChanged(const gfx::Rect& new_bounds) {}
+
+void DemoWindow::OnDamageRect(const gfx::Rect& damaged_region) {}
+
+void DemoWindow::DispatchEvent(Event* event) {
+ if (event->IsKeyEvent() && event->AsKeyEvent()->code() == DomCode::US_Q)
+ Quit();
+}
+
+void DemoWindow::OnCloseRequest() {
+ Quit();
+}
+
+void DemoWindow::OnClosed() {}
+
+void DemoWindow::OnWindowStateChanged(PlatformWindowState new_state) {}
+
+void DemoWindow::OnLostCapture() {}
+
+void DemoWindow::OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
+ float device_pixel_ratio) {
+ DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
+ widget_ = widget;
+}
+
+void DemoWindow::OnAcceleratedWidgetDestroyed() {
+ NOTREACHED();
+}
+
+void DemoWindow::OnActivationChanged(bool active) {}
+
+void DemoWindow::StartOnGpu() {
+ renderer_ =
+ renderer_factory_->CreateRenderer(GetAcceleratedWidget(), GetSize());
+ if (!renderer_->Initialize())
+ LOG(ERROR) << "Failed to initialize renderer.";
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/demo/demo_window.h b/chromium/ui/ozone/demo/demo_window.h
new file mode 100644
index 00000000000..6a41df1252b
--- /dev/null
+++ b/chromium/ui/ozone/demo/demo_window.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_DEMO_DEMO_WINDOW_H_
+#define UI_OZONE_DEMO_DEMO_WINDOW_H_
+
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+class Event;
+class PlatformWindow;
+class Renderer;
+class RendererFactory;
+class WindowManager;
+
+class DemoWindow : public PlatformWindowDelegate {
+ public:
+ DemoWindow(WindowManager* window_manager,
+ RendererFactory* renderer_factory,
+ const gfx::Rect& bounds);
+ ~DemoWindow() override;
+
+ gfx::AcceleratedWidget GetAcceleratedWidget();
+
+ gfx::Size GetSize();
+
+ void Start();
+ void Quit();
+
+ // PlatformWindowDelegate:
+ void OnBoundsChanged(const gfx::Rect& new_bounds) override;
+ void OnDamageRect(const gfx::Rect& damaged_region) override;
+ void DispatchEvent(Event* event) override;
+ void OnCloseRequest() override;
+ void OnClosed() override;
+ void OnWindowStateChanged(PlatformWindowState new_state) override;
+ void OnLostCapture() override;
+ void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
+ float device_pixel_ratio) override;
+ void OnAcceleratedWidgetDestroyed() override;
+ void OnActivationChanged(bool active) override;
+
+ private:
+ // Since we pretend to have a GPU process, we should also pretend to
+ // initialize the GPU resources via a posted task.
+ void StartOnGpu();
+
+ WindowManager* window_manager_; // Not owned.
+ RendererFactory* renderer_factory_; // Not owned.
+
+ std::unique_ptr<Renderer> renderer_;
+
+ // Window-related state.
+ std::unique_ptr<PlatformWindow> platform_window_;
+ gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
+
+ base::WeakPtrFactory<DemoWindow> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DemoWindow);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_DEMO_WINDOW_H_
diff --git a/chromium/ui/ozone/demo/ozone_demo.cc b/chromium/ui/ozone/demo/ozone_demo.cc
index fc989906f2e..6806dbe84fe 100644
--- a/chromium/ui/ozone/demo/ozone_demo.cc
+++ b/chromium/ui/ozone/demo/ozone_demo.cc
@@ -2,334 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <utility>
+#include <iostream>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task_scheduler/task_scheduler.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "components/tracing/common/trace_to_console.h"
#include "components/tracing/common/tracing_switches.h"
-#include "ui/display/types/display_snapshot.h"
-#include "ui/display/types/native_display_delegate.h"
-#include "ui/display/types/native_display_observer.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gl/gl_surface.h"
-#include "ui/gl/init/gl_factory.h"
-#include "ui/ozone/demo/skia_renderer.h"
-#include "ui/ozone/demo/software_renderer.h"
-#include "ui/ozone/demo/surfaceless_skia_renderer.h"
-#include "ui/ozone/public/ozone_gpu_test_helper.h"
+#include "ui/ozone/demo/window_manager.h"
#include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/ozone_switches.h"
-#include "ui/platform_window/platform_window.h"
-#include "ui/platform_window/platform_window_delegate.h"
-const int kTestWindowWidth = 800;
-const int kTestWindowHeight = 600;
-
-const char kDisableGpu[] = "disable-gpu";
-const char kDisableSurfaceless[] = "disable-surfaceless";
-
-const char kWindowSize[] = "window-size";
-
-class DemoWindow;
-
-scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) {
- scoped_refptr<gl::GLSurface> surface;
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableSurfaceless))
- surface = gl::init::CreateSurfacelessViewGLSurface(widget);
- if (!surface)
- surface = gl::init::CreateViewGLSurface(widget);
- return surface;
-}
-
-class RendererFactory {
- public:
- enum RendererType {
- SKIA,
- SOFTWARE,
- };
-
- RendererFactory();
- ~RendererFactory();
-
- bool Initialize();
- std::unique_ptr<ui::Renderer> CreateRenderer(gfx::AcceleratedWidget widget,
- const gfx::Size& size);
-
- private:
- RendererType type_ = SOFTWARE;
-
- // Helper for applications that do GL on main thread.
- ui::OzoneGpuTestHelper gpu_helper_;
-
- DISALLOW_COPY_AND_ASSIGN(RendererFactory);
-};
-
-class WindowManager : public display::NativeDisplayObserver {
- public:
- explicit WindowManager(const base::Closure& quit_closure);
- ~WindowManager() override;
-
- void Quit();
-
- void AddWindow(DemoWindow* window);
- void RemoveWindow(DemoWindow* window);
-
- private:
- void OnDisplaysAquired(
- const std::vector<display::DisplaySnapshot*>& displays);
- void OnDisplayConfigured(const gfx::Rect& bounds, bool success);
-
- // display::NativeDisplayDelegate:
- void OnConfigurationChanged() override;
- void OnDisplaySnapshotsInvalidated() override;
-
- std::unique_ptr<display::NativeDisplayDelegate> delegate_;
- base::Closure quit_closure_;
- RendererFactory renderer_factory_;
- std::vector<std::unique_ptr<DemoWindow>> windows_;
-
- // Flags used to keep track of the current state of display configuration.
- //
- // True if configuring the displays. In this case a new display configuration
- // isn't started.
- bool is_configuring_ = false;
-
- // If |is_configuring_| is true and another display configuration event
- // happens, the event is deferred. This is set to true and a display
- // configuration will be scheduled after the current one finishes.
- bool should_configure_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManager);
-};
-
-class DemoWindow : public ui::PlatformWindowDelegate {
- public:
- DemoWindow(WindowManager* window_manager,
- RendererFactory* renderer_factory,
- const gfx::Rect& bounds)
- : window_manager_(window_manager),
- renderer_factory_(renderer_factory),
- weak_ptr_factory_(this) {
- platform_window_ =
- ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
- platform_window_->Show();
- }
- ~DemoWindow() override {}
-
- gfx::AcceleratedWidget GetAcceleratedWidget() {
- // TODO(spang): We should start rendering asynchronously.
- DCHECK_NE(widget_, gfx::kNullAcceleratedWidget)
- << "Widget not available synchronously";
- return widget_;
- }
-
- gfx::Size GetSize() { return platform_window_->GetBounds().size(); }
-
- void Start() {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&DemoWindow::StartOnGpu, weak_ptr_factory_.GetWeakPtr()));
- }
-
- void Quit() {
- window_manager_->Quit();
- }
-
- // PlatformWindowDelegate:
- void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
- void OnDamageRect(const gfx::Rect& damaged_region) override {}
- void DispatchEvent(ui::Event* event) override {
- if (event->IsKeyEvent() && event->AsKeyEvent()->code() == ui::DomCode::US_Q)
- Quit();
- }
- void OnCloseRequest() override { Quit(); }
- void OnClosed() override {}
- void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
- void OnLostCapture() override {}
- void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
- float device_pixel_ratio) override {
- DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
- widget_ = widget;
- }
- void OnAcceleratedWidgetDestroyed() override {
- NOTREACHED();
- }
- void OnActivationChanged(bool active) override {}
-
- private:
- // Since we pretend to have a GPU process, we should also pretend to
- // initialize the GPU resources via a posted task.
- void StartOnGpu() {
- renderer_ =
- renderer_factory_->CreateRenderer(GetAcceleratedWidget(), GetSize());
- if (!renderer_->Initialize())
- LOG(ERROR) << "Failed to initialize renderer.";
- }
-
- WindowManager* window_manager_; // Not owned.
- RendererFactory* renderer_factory_; // Not owned.
-
- std::unique_ptr<ui::Renderer> renderer_;
-
- // Window-related state.
- std::unique_ptr<ui::PlatformWindow> platform_window_;
- gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
-
- base::WeakPtrFactory<DemoWindow> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DemoWindow);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// RendererFactory implementation:
-
-RendererFactory::RendererFactory() {
-}
-
-RendererFactory::~RendererFactory() {
-}
-
-bool RendererFactory::Initialize() {
- ui::OzonePlatform::InitParams params;
- params.single_process = true;
- ui::OzonePlatform::InitializeForGPU(params);
- ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
-
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() &&
- gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) {
- type_ = SKIA;
- } else {
- type_ = SOFTWARE;
- }
-
- return true;
-}
-
-std::unique_ptr<ui::Renderer> RendererFactory::CreateRenderer(
- gfx::AcceleratedWidget widget,
- const gfx::Size& size) {
- switch (type_) {
- case SKIA: {
- scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget);
- if (!surface)
- LOG(FATAL) << "Failed to create GL surface";
- if (surface->IsSurfaceless()) {
- return std::make_unique<ui::SurfacelessSkiaRenderer>(widget, surface,
- size);
- }
- return std::make_unique<ui::SkiaRenderer>(widget, surface, size);
- }
- case SOFTWARE:
- return std::make_unique<ui::SoftwareRenderer>(widget, size);
- }
-
- return nullptr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// WindowManager implementation:
-
-WindowManager::WindowManager(const base::Closure& quit_closure)
- : delegate_(
- ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate()),
- quit_closure_(quit_closure) {
- if (!renderer_factory_.Initialize())
- LOG(FATAL) << "Failed to initialize renderer factory";
-
- if (delegate_) {
- delegate_->AddObserver(this);
- delegate_->Initialize();
- OnConfigurationChanged();
- } else {
- LOG(WARNING) << "No display delegate; falling back to test window";
- int width = kTestWindowWidth;
- int height = kTestWindowHeight;
- sscanf(base::CommandLine::ForCurrentProcess()
- ->GetSwitchValueASCII(kWindowSize)
- .c_str(),
- "%dx%d", &width, &height);
-
- DemoWindow* window = new DemoWindow(this, &renderer_factory_,
- gfx::Rect(gfx::Size(width, height)));
- window->Start();
- }
-}
-
-WindowManager::~WindowManager() {
- if (delegate_)
- delegate_->RemoveObserver(this);
-}
-
-void WindowManager::Quit() {
- quit_closure_.Run();
-}
-
-void WindowManager::OnConfigurationChanged() {
- if (is_configuring_) {
- should_configure_ = true;
- return;
- }
-
- is_configuring_ = true;
- delegate_->GetDisplays(
- base::Bind(&WindowManager::OnDisplaysAquired, base::Unretained(this)));
-}
-
-void WindowManager::OnDisplaySnapshotsInvalidated() {}
-
-void WindowManager::OnDisplaysAquired(
- const std::vector<display::DisplaySnapshot*>& displays) {
- windows_.clear();
-
- gfx::Point origin;
- for (auto* display : displays) {
- if (!display->native_mode()) {
- LOG(ERROR) << "Display " << display->display_id()
- << " doesn't have a native mode";
- continue;
- }
-
- delegate_->Configure(
- *display, display->native_mode(), origin,
- base::Bind(&WindowManager::OnDisplayConfigured, base::Unretained(this),
- gfx::Rect(origin, display->native_mode()->size())));
- origin.Offset(display->native_mode()->size().width(), 0);
- }
- is_configuring_ = false;
-
- if (should_configure_) {
- should_configure_ = false;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&WindowManager::OnConfigurationChanged,
- base::Unretained(this)));
- }
-}
-
-void WindowManager::OnDisplayConfigured(const gfx::Rect& bounds, bool success) {
- if (success) {
- std::unique_ptr<DemoWindow> window(
- new DemoWindow(this, &renderer_factory_, bounds));
- window->Start();
- windows_.push_back(std::move(window));
- } else {
- LOG(ERROR) << "Failed to configure display at " << bounds.ToString();
- }
-}
+const char kHelp[] = "help";
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
@@ -341,6 +30,25 @@ int main(int argc, char** argv) {
logging::LoggingSettings settings;
logging::InitLogging(settings);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelp)) {
+ std::cout <<
+ "Usage:\n\n"
+ " --enable-drm-atomic Use the atomic KMS API\n"
+ " --disable-gpu Force software rendering\n"
+ " --disable-surfaceless Don't use surfaceless EGL\n"
+ " --window-size=WIDTHxHEIGHT Specify window size\n"
+ " --use-ddl Use SkDeferredDisplayList\n"
+ " --partial-primary-plane "
+ "Use smaller than fullscreen primary plane\n"
+ " --enable-overlay Use an overlay plane\n"
+ " --disable-primary-plane Don't use the primary plane\n";
+
+ // TODO(hoegsberg): We should add a little more help text about how these
+ // options interact and depend on each other.
+
+ exit(EXIT_SUCCESS);
+ }
+
// Initialize tracing.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kTraceToConsole)) {
@@ -363,7 +71,7 @@ int main(int argc, char** argv) {
base::RunLoop run_loop;
- WindowManager window_manager(run_loop.QuitClosure());
+ ui::WindowManager window_manager(run_loop.QuitClosure());
run_loop.Run();
diff --git a/chromium/ui/ozone/demo/renderer_factory.cc b/chromium/ui/ozone/demo/renderer_factory.cc
new file mode 100644
index 00000000000..10a01103786
--- /dev/null
+++ b/chromium/ui/ozone/demo/renderer_factory.cc
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/demo/renderer_factory.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/init/gl_factory.h"
+#include "ui/ozone/demo/skia_renderer.h"
+#include "ui/ozone/demo/software_renderer.h"
+#include "ui/ozone/demo/surfaceless_skia_renderer.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+namespace {
+
+const char kDisableSurfaceless[] = "disable-surfaceless";
+const char kDisableGpu[] = "disable-gpu";
+
+scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) {
+ scoped_refptr<gl::GLSurface> surface;
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableSurfaceless))
+ surface = gl::init::CreateSurfacelessViewGLSurface(widget);
+ if (!surface)
+ surface = gl::init::CreateViewGLSurface(widget);
+ return surface;
+}
+
+} // namespace
+
+RendererFactory::RendererFactory() {}
+
+RendererFactory::~RendererFactory() {}
+
+bool RendererFactory::Initialize() {
+ OzonePlatform::InitParams params;
+ params.single_process = true;
+ OzonePlatform::InitializeForGPU(params);
+ OzonePlatform::GetInstance()->AfterSandboxEntry();
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() &&
+ gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) {
+ type_ = SKIA;
+ } else {
+ type_ = SOFTWARE;
+ }
+
+ return true;
+}
+
+std::unique_ptr<Renderer> RendererFactory::CreateRenderer(
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size) {
+ switch (type_) {
+ case SKIA: {
+ scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget);
+ if (!surface)
+ LOG(FATAL) << "Failed to create GL surface";
+ if (surface->IsSurfaceless()) {
+ return std::make_unique<SurfacelessSkiaRenderer>(widget, surface, size);
+ }
+ return std::make_unique<SkiaRenderer>(widget, surface, size);
+ }
+ case SOFTWARE:
+ return std::make_unique<SoftwareRenderer>(widget, size);
+ }
+
+ return nullptr;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/demo/renderer_factory.h b/chromium/ui/ozone/demo/renderer_factory.h
new file mode 100644
index 00000000000..f87aeaea6d3
--- /dev/null
+++ b/chromium/ui/ozone/demo/renderer_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_DEMO_RENDERER_FACTORY_H_
+#define UI_OZONE_DEMO_RENDERER_FACTORY_H_
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
+
+namespace ui {
+
+class Renderer;
+
+class RendererFactory {
+ public:
+ enum RendererType {
+ SKIA,
+ SOFTWARE,
+ };
+
+ RendererFactory();
+ ~RendererFactory();
+
+ bool Initialize();
+ std::unique_ptr<Renderer> CreateRenderer(gfx::AcceleratedWidget widget,
+ const gfx::Size& size);
+
+ private:
+ RendererType type_ = SOFTWARE;
+
+ // Helper for applications that do GL on main thread.
+ OzoneGpuTestHelper gpu_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_RENDERER_FACTORY_H_
diff --git a/chromium/ui/ozone/demo/skia_renderer.cc b/chromium/ui/ozone/demo/skia_renderer.cc
index a8d7947ed8f..71154c08925 100644
--- a/chromium/ui/ozone/demo/skia_renderer.cc
+++ b/chromium/ui/ozone/demo/skia_renderer.cc
@@ -85,13 +85,13 @@ void SkiaRenderer::RenderFrame() {
if (!sk_surface_) {
GrGLFramebufferInfo framebuffer_info;
framebuffer_info.fFBOID = 0;
+ framebuffer_info.fFormat = GL_RGBA8;
GrBackendRenderTarget render_target(size_.width(), size_.height(), 0, 8,
- kRGBA_8888_GrPixelConfig,
framebuffer_info);
sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
- gr_context_.get(), render_target, kBottomLeft_GrSurfaceOrigin, nullptr,
- &surface_props);
+ gr_context_.get(), render_target, kBottomLeft_GrSurfaceOrigin,
+ kRGBA_8888_SkColorType, nullptr, &surface_props);
}
if (use_ddl_) {
diff --git a/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc b/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc
index fef66dff8af..c3bce8be2d5 100644
--- a/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc
+++ b/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc
@@ -114,7 +114,7 @@ bool SurfacelessSkiaRenderer::BufferWrapper::Initialize(
->GetSurfaceFactoryOzone()
->CreateNativePixmap(widget, size, format, gfx::BufferUsage::SCANOUT);
scoped_refptr<gl::GLImageNativePixmap> image(
- new gl::GLImageNativePixmap(size, GL_RGB));
+ new gl::GLImageNativePixmap(size, GL_BGRA_EXT));
if (!image->Initialize(pixmap.get(), format)) {
LOG(ERROR) << "Failed to create GLImage";
return false;
@@ -130,12 +130,12 @@ bool SurfacelessSkiaRenderer::BufferWrapper::Initialize(
GrGLTextureInfo texture_info;
texture_info.fTarget = GL_TEXTURE_2D;
texture_info.fID = gl_tex_;
- texture_info.fFormat = GL_RGBA;
+ texture_info.fFormat = GL_BGRA8_EXT;
GrBackendTexture backend_texture(size_.width(), size_.height(),
- kRGBA_8888_GrPixelConfig, texture_info);
- sk_surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
- gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, 0, nullptr,
- nullptr);
+ GrMipMapped::kNo, texture_info);
+ sk_surface_ = SkSurface::MakeFromBackendTexture(
+ gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, 0,
+ kBGRA_8888_SkColorType, nullptr, nullptr);
if (!sk_surface_) {
LOG(ERROR) << "Failed to create skia surface";
return false;
@@ -184,7 +184,7 @@ bool SurfacelessSkiaRenderer::Initialize() {
overlay_buffer_[i]->Initialize(gr_context_.get(),
gfx::kNullAcceleratedWidget, overlay_size);
SkCanvas* sk_canvas = overlay_buffer_[i]->sk_surface()->getCanvas();
- sk_canvas->clear(SkColorSetARGB(255, 255 * i, 255, 0));
+ sk_canvas->clear(SkColorSetARGB(96, 255 * i, 255, 0));
}
}
@@ -246,13 +246,13 @@ void SurfacelessSkiaRenderer::RenderFrame() {
CHECK(overlay_list.front().overlay_handled);
gl_surface_->ScheduleOverlayPlane(
0, gfx::OVERLAY_TRANSFORM_NONE, buffers_[back_buffer_]->image(),
- primary_plane_rect_, gfx::RectF(0, 0, 1, 1));
+ primary_plane_rect_, gfx::RectF(0, 0, 1, 1), /* enable_blend */ true);
}
if (overlay_buffer_[0] && overlay_list.back().overlay_handled) {
- gl_surface_->ScheduleOverlayPlane(1, gfx::OVERLAY_TRANSFORM_NONE,
- overlay_buffer_[back_buffer_]->image(),
- overlay_rect, gfx::RectF(0, 0, 1, 1));
+ gl_surface_->ScheduleOverlayPlane(
+ 1, gfx::OVERLAY_TRANSFORM_NONE, overlay_buffer_[back_buffer_]->image(),
+ overlay_rect, gfx::RectF(0, 0, 1, 1), /* enable_blend */ true);
}
back_buffer_ ^= 1;
diff --git a/chromium/ui/ozone/demo/window_manager.cc b/chromium/ui/ozone/demo/window_manager.cc
new file mode 100644
index 00000000000..9fb74d7e1c5
--- /dev/null
+++ b/chromium/ui/ozone/demo/window_manager.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/demo/window_manager.h"
+
+#include "base/command_line.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/ozone/demo/demo_window.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+namespace {
+
+const int kTestWindowWidth = 800;
+const int kTestWindowHeight = 600;
+
+const char kWindowSize[] = "window-size";
+
+} // namespace
+
+WindowManager::WindowManager(base::OnceClosure quit_closure)
+ : delegate_(
+ ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate()),
+ quit_closure_(std::move(quit_closure)) {
+ if (!renderer_factory_.Initialize())
+ LOG(FATAL) << "Failed to initialize renderer factory";
+
+ if (delegate_) {
+ delegate_->AddObserver(this);
+ delegate_->Initialize();
+ OnConfigurationChanged();
+ } else {
+ LOG(WARNING) << "No display delegate; falling back to test window";
+ int width = kTestWindowWidth;
+ int height = kTestWindowHeight;
+ sscanf(base::CommandLine::ForCurrentProcess()
+ ->GetSwitchValueASCII(kWindowSize)
+ .c_str(),
+ "%dx%d", &width, &height);
+
+ DemoWindow* window = new DemoWindow(this, &renderer_factory_,
+ gfx::Rect(gfx::Size(width, height)));
+ window->Start();
+ }
+}
+
+WindowManager::~WindowManager() {
+ if (delegate_)
+ delegate_->RemoveObserver(this);
+}
+
+void WindowManager::Quit() {
+ std::move(quit_closure_).Run();
+}
+
+void WindowManager::OnConfigurationChanged() {
+ if (is_configuring_) {
+ should_configure_ = true;
+ return;
+ }
+
+ is_configuring_ = true;
+ delegate_->GetDisplays(base::BindRepeating(&WindowManager::OnDisplaysAquired,
+ base::Unretained(this)));
+}
+
+void WindowManager::OnDisplaySnapshotsInvalidated() {}
+
+void WindowManager::OnDisplaysAquired(
+ const std::vector<display::DisplaySnapshot*>& displays) {
+ windows_.clear();
+
+ gfx::Point origin;
+ for (auto* display : displays) {
+ if (!display->native_mode()) {
+ LOG(ERROR) << "Display " << display->display_id()
+ << " doesn't have a native mode";
+ continue;
+ }
+
+ delegate_->Configure(
+ *display, display->native_mode(), origin,
+ base::BindRepeating(&WindowManager::OnDisplayConfigured,
+ base::Unretained(this),
+ gfx::Rect(origin, display->native_mode()->size())));
+ origin.Offset(display->native_mode()->size().width(), 0);
+ }
+ is_configuring_ = false;
+
+ if (should_configure_) {
+ should_configure_ = false;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindRepeating(&WindowManager::OnConfigurationChanged,
+ base::Unretained(this)));
+ }
+}
+
+void WindowManager::OnDisplayConfigured(const gfx::Rect& bounds, bool success) {
+ if (success) {
+ std::unique_ptr<DemoWindow> window(
+ new DemoWindow(this, &renderer_factory_, bounds));
+ window->Start();
+ windows_.push_back(std::move(window));
+ } else {
+ LOG(ERROR) << "Failed to configure display at " << bounds.ToString();
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/demo/window_manager.h b/chromium/ui/ozone/demo/window_manager.h
new file mode 100644
index 00000000000..d15590843fc
--- /dev/null
+++ b/chromium/ui/ozone/demo/window_manager.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_DEMO_WINDOW_MANAGER_H_
+#define UI_OZONE_DEMO_WINDOW_MANAGER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "ui/display/types/native_display_observer.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/demo/renderer_factory.h"
+
+namespace display {
+
+class DisplaySnapshot;
+class NativeDisplayDelegate;
+
+} // namespace display
+
+namespace ui {
+
+class DemoWindow;
+
+class WindowManager : public display::NativeDisplayObserver {
+ public:
+ explicit WindowManager(base::OnceClosure quit_closure);
+ ~WindowManager() override;
+
+ void Quit();
+
+ void AddWindow(DemoWindow* window);
+ void RemoveWindow(DemoWindow* window);
+
+ private:
+ void OnDisplaysAquired(
+ const std::vector<display::DisplaySnapshot*>& displays);
+ void OnDisplayConfigured(const gfx::Rect& bounds, bool success);
+
+ // display::NativeDisplayDelegate:
+ void OnConfigurationChanged() override;
+ void OnDisplaySnapshotsInvalidated() override;
+
+ std::unique_ptr<display::NativeDisplayDelegate> delegate_;
+ base::OnceClosure quit_closure_;
+ RendererFactory renderer_factory_;
+ std::vector<std::unique_ptr<DemoWindow>> windows_;
+
+ // Flags used to keep track of the current state of display configuration.
+ //
+ // True if configuring the displays. In this case a new display configuration
+ // isn't started.
+ bool is_configuring_ = false;
+
+ // If |is_configuring_| is true and another display configuration event
+ // happens, the event is deferred. This is set to true and a display
+ // configuration will be scheduled after the current one finishes.
+ bool should_configure_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_WINDOW_MANAGER_H_
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 52a42f83617..c2948020455 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
@@ -9,7 +9,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap.h"
-#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/gl/gl_image_native_pixmap.h"
#include "ui/gl/test/gl_image_test_template.h"
#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
@@ -26,7 +25,7 @@ template <gfx::BufferUsage usage, gfx::BufferFormat format>
class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
public:
GLImageNativePixmapTestDelegate() {
- ui::CreateClientNativePixmapFactoryOzone();
+ client_native_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone();
}
~GLImageNativePixmapTestDelegate() override = default;
@@ -41,9 +40,8 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
DCHECK(pixmap);
if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE ||
usage == gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE) {
- auto client_pixmap =
- gfx::ClientNativePixmapFactory::GetInstance()->ImportFromHandle(
- pixmap->ExportHandle(), size, usage);
+ auto client_pixmap = client_native_pixmap_factory_->ImportFromHandle(
+ pixmap->ExportHandle(), size, usage);
bool mapped = client_pixmap->Map();
EXPECT_TRUE(mapped);
@@ -77,6 +75,8 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
}
private:
+ std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_;
+
DISALLOW_COPY_AND_ASSIGN(GLImageNativePixmapTestDelegate);
};
diff --git a/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc b/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
index 607bf221064..4aa44c770ba 100644
--- a/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
+++ b/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
@@ -5,7 +5,6 @@
#include "ui/ozone/platform/cast/client_native_pixmap_factory_cast.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/client_native_pixmap_factory.h"
@@ -39,7 +38,7 @@ class ClientNativePixmapFactoryCast : public gfx::ClientNativePixmapFactory {
// ClientNativePixmapFactoryCast implementation:
bool IsConfigurationSupported(gfx::BufferFormat format,
gfx::BufferUsage usage) const override {
- return format == gfx::BufferFormat::RGBA_8888 &&
+ return format == gfx::BufferFormat::BGRA_8888 &&
usage == gfx::BufferUsage::SCANOUT;
}
diff --git a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
index 4066ed416c9..33d0651f58b 100644
--- a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
+++ b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
@@ -11,7 +11,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "chromecast/base/chromecast_switches.h"
#include "chromecast/public/cast_egl_platform.h"
diff --git a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc
index dd50b11cfec..7097dfbde90 100644
--- a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc
+++ b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc
@@ -5,7 +5,6 @@
#include "ui/ozone/platform/cast/gl_surface_cast.h"
#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "chromecast/base/cast_features.h"
#include "chromecast/base/chromecast_switches.h"
@@ -100,9 +99,10 @@ bool GLSurfaceCast::ScheduleOverlayPlane(int z_order,
gfx::OverlayTransform transform,
gl::GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect,
- crop_rect);
+ crop_rect, enable_blend);
}
EGLConfig GLSurfaceCast::GetConfig() {
diff --git a/chromium/ui/ozone/platform/cast/gl_surface_cast.h b/chromium/ui/ozone/platform/cast/gl_surface_cast.h
index 3d3a5412021..2bd8fa16ccf 100644
--- a/chromium/ui/ozone/platform/cast/gl_surface_cast.h
+++ b/chromium/ui/ozone/platform/cast/gl_surface_cast.h
@@ -35,7 +35,8 @@ class GLSurfaceCast : public gl::NativeViewGLSurfaceEGL {
gfx::OverlayTransform transform,
gl::GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
EGLConfig GetConfig() override;
protected:
diff --git a/chromium/ui/ozone/platform/cast/overlay_manager_cast.cc b/chromium/ui/ozone/platform/cast/overlay_manager_cast.cc
index 9ce4f0a3e39..6a34f691350 100644
--- a/chromium/ui/ozone/platform/cast/overlay_manager_cast.cc
+++ b/chromium/ui/ozone/platform/cast/overlay_manager_cast.cc
@@ -4,72 +4,18 @@
#include "ui/ozone/platform/cast/overlay_manager_cast.h"
-#include "base/lazy_instance.h"
-#include "base/memory/ptr_util.h"
-#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
namespace ui {
namespace {
-base::LazyInstance<OverlayManagerCast::OverlayCompositedCallback>::
- DestructorAtExit g_overlay_composited_callback = LAZY_INSTANCE_INITIALIZER;
-
-// Translates a gfx::OverlayTransform into a VideoPlane::Transform.
-// Could be just a lookup table once we have unit tests for this code
-// to ensure it stays in sync with OverlayTransform.
-chromecast::media::VideoPlane::Transform ConvertTransform(
- gfx::OverlayTransform transform) {
- switch (transform) {
- case gfx::OVERLAY_TRANSFORM_NONE:
- return chromecast::media::VideoPlane::TRANSFORM_NONE;
- case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
- return chromecast::media::VideoPlane::FLIP_HORIZONTAL;
- case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
- return chromecast::media::VideoPlane::FLIP_VERTICAL;
- case gfx::OVERLAY_TRANSFORM_ROTATE_90:
- return chromecast::media::VideoPlane::ROTATE_90;
- case gfx::OVERLAY_TRANSFORM_ROTATE_180:
- return chromecast::media::VideoPlane::ROTATE_180;
- case gfx::OVERLAY_TRANSFORM_ROTATE_270:
- return chromecast::media::VideoPlane::ROTATE_270;
- default:
- NOTREACHED();
- return chromecast::media::VideoPlane::TRANSFORM_NONE;
- }
-}
-
class OverlayCandidatesCast : public OverlayCandidatesOzone {
public:
OverlayCandidatesCast() {}
- void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces) override;
+ void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces) override {}
};
-void OverlayCandidatesCast::CheckOverlaySupport(
- OverlaySurfaceCandidateList* surfaces) {
- for (auto& candidate : *surfaces) {
- if (candidate.plane_z_order != -1)
- continue;
-
- candidate.overlay_handled = true;
-
- // Compositor requires all overlay rectangles to have integer coords.
- candidate.display_rect =
- gfx::RectF(gfx::ToEnclosedRect(candidate.display_rect));
-
- chromecast::RectF display_rect(
- candidate.display_rect.x(), candidate.display_rect.y(),
- candidate.display_rect.width(), candidate.display_rect.height());
-
- // Update video plane geometry + transform to match compositor quad.
- if (!g_overlay_composited_callback.Get().is_null())
- g_overlay_composited_callback.Get().Run(
- display_rect, ConvertTransform(candidate.transform));
- return;
- }
-}
-
} // namespace
OverlayManagerCast::OverlayManagerCast() {
@@ -83,10 +29,4 @@ OverlayManagerCast::CreateOverlayCandidates(gfx::AcceleratedWidget w) {
return std::make_unique<OverlayCandidatesCast>();
}
-// static
-void OverlayManagerCast::SetOverlayCompositedCallback(
- const OverlayCompositedCallback& cb) {
- g_overlay_composited_callback.Get() = cb;
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/cast/overlay_manager_cast.h b/chromium/ui/ozone/platform/cast/overlay_manager_cast.h
index 0ddf98d67f5..6d9963b4f4a 100644
--- a/chromium/ui/ozone/platform/cast/overlay_manager_cast.h
+++ b/chromium/ui/ozone/platform/cast/overlay_manager_cast.h
@@ -7,16 +7,12 @@
#include <memory>
-#include "base/callback.h"
#include "base/macros.h"
-#include "chromecast/public/graphics_types.h"
-#include "chromecast/public/video_plane.h"
-#include "ui/ozone/ozone_export.h"
#include "ui/ozone/public/overlay_manager_ozone.h"
namespace ui {
-class OZONE_EXPORT OverlayManagerCast : public OverlayManagerOzone {
+class OverlayManagerCast : public OverlayManagerOzone {
public:
OverlayManagerCast();
~OverlayManagerCast() override;
@@ -25,16 +21,7 @@ class OZONE_EXPORT OverlayManagerCast : public OverlayManagerOzone {
std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget w) override;
- // Callback that's made whenever an overlay quad is processed
- // in the compositor. Used to allow hardware video plane to
- // be positioned to match compositor hole.
- using OverlayCompositedCallback =
- base::Callback<void(const chromecast::RectF&,
- chromecast::media::VideoPlane::Transform)>;
- static void SetOverlayCompositedCallback(const OverlayCompositedCallback& cb);
-
private:
-
DISALLOW_COPY_AND_ASSIGN(OverlayManagerCast);
};
diff --git a/chromium/ui/ozone/platform/cast/platform_window_cast.cc b/chromium/ui/ozone/platform/cast/platform_window_cast.cc
index d5a33378cd5..a24276ca87a 100644
--- a/chromium/ui/ozone/platform/cast/platform_window_cast.cc
+++ b/chromium/ui/ozone/platform/cast/platform_window_cast.cc
@@ -18,15 +18,13 @@ PlatformWindowCast::PlatformWindowCast(PlatformWindowDelegate* delegate,
widget_ = (bounds.width() << 16) + bounds.height();
delegate_->OnAcceleratedWidgetAvailable(widget_, 1.f);
- if (ui::PlatformEventSource::GetInstance()) {
- ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
- }
+ if (PlatformEventSource::GetInstance())
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
}
PlatformWindowCast::~PlatformWindowCast() {
- if (ui::PlatformEventSource::GetInstance()) {
- ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
- }
+ if (PlatformEventSource::GetInstance())
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
gfx::Rect PlatformWindowCast::GetBounds() {
@@ -41,16 +39,19 @@ void PlatformWindowCast::SetBounds(const gfx::Rect& bounds) {
void PlatformWindowCast::SetTitle(const base::string16& title) {
}
+bool PlatformWindowCast::HasCapture() const {
+ return false;
+}
+
PlatformImeController* PlatformWindowCast::GetPlatformImeController() {
return nullptr;
}
-bool PlatformWindowCast::CanDispatchEvent(const ui::PlatformEvent& ne) {
+bool PlatformWindowCast::CanDispatchEvent(const PlatformEvent& ne) {
return true;
}
-uint32_t PlatformWindowCast::DispatchEvent(
- const ui::PlatformEvent& native_event) {
+uint32_t PlatformWindowCast::DispatchEvent(const PlatformEvent& native_event) {
DispatchEventFromNativeUiEvent(
native_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
diff --git a/chromium/ui/ozone/platform/cast/platform_window_cast.h b/chromium/ui/ozone/platform/cast/platform_window_cast.h
index 4a494f2c830..a7930ee26fa 100644
--- a/chromium/ui/ozone/platform/cast/platform_window_cast.h
+++ b/chromium/ui/ozone/platform/cast/platform_window_cast.h
@@ -31,6 +31,7 @@ class PlatformWindowCast : public PlatformWindow,
void PrepareForShutdown() override {}
void SetCapture() override {}
void ReleaseCapture() override {}
+ bool HasCapture() const override;
void ToggleFullscreen() override {}
void Maximize() override {}
void Minimize() override {}
diff --git a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc
index 234c3f90d71..4718585dcd0 100644
--- a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -69,7 +69,8 @@ class CastPixmap : public gfx::NativePixmap {
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) override {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override {
parent_->OnOverlayScheduled(display_bounds);
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index 99fc0d66bf2..7ff7018bbb6 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -114,7 +114,7 @@ source_set("gbm") {
deps = [
"//base",
"//ipc",
- "//mojo/common:common_base",
+ "//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//services/ui/public/interfaces:constants",
"//skia",
diff --git a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
index f8dd781ebf4..8e363e69280 100644
--- a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
#include "ui/gfx/native_pixmap_handle.h"
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc
index d4c3dd51037..77054a23dbf 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc
@@ -14,7 +14,7 @@
#include <utility>
#include "base/containers/flat_map.h"
-#include "base/memory/ptr_util.h"
+#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/util/edid_parser.h"
@@ -381,7 +381,7 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
const base::FilePath& sys_path,
size_t device_index,
const gfx::Point& origin) {
- int64_t display_id = ConnectorIndex(device_index, info->index());
+ const uint8_t display_index = ConnectorIndex(device_index, info->index());
const gfx::Size physical_size =
gfx::Size(info->connector()->mmWidth, info->connector()->mmHeight);
const display::DisplayConnectionType type = GetDisplayType(info->connector());
@@ -391,29 +391,31 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
HasColorCorrectionMatrix(fd, info->crtc());
const gfx::Size maximum_cursor_size = GetMaximumCursorSize(fd);
- std::vector<uint8_t> edid;
std::string display_name;
- int64_t product_id = display::DisplaySnapshot::kInvalidProductID;
+ int64_t display_id = display_index;
+ int64_t product_code = display::DisplaySnapshot::kInvalidProductCode;
+ int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
bool has_overscan = false;
gfx::ColorSpace display_color_space;
-
- // This is the size of the active pixels from the first detailed timing
- // descriptor in the EDID.
+ // Active pixels size from the first detailed timing descriptor in the EDID.
gfx::Size active_pixel_size;
ScopedDrmPropertyBlobPtr edid_blob(
GetDrmPropertyBlob(fd, info->connector(), "EDID"));
+ std::vector<uint8_t> edid;
if (edid_blob) {
edid.assign(static_cast<uint8_t*>(edid_blob->data),
static_cast<uint8_t*>(edid_blob->data) + edid_blob->length);
- display::GetDisplayIdFromEDID(edid, display_id, &display_id, &product_id);
-
- display::ParseOutputDeviceData(edid, nullptr, nullptr, &display_name,
- &active_pixel_size, nullptr);
- display::ParseOutputOverscanFlag(edid, &has_overscan);
-
- display_color_space = GetColorSpaceFromEdid(edid);
+ display::EdidParser edid_parser(edid);
+ display_name = edid_parser.display_name();
+ active_pixel_size = edid_parser.active_pixel_size();
+ product_code = edid_parser.GetProductCode();
+ display_id = edid_parser.GetDisplayId(display_index);
+ year_of_manufacture = edid_parser.year_of_manufacture();
+ has_overscan =
+ edid_parser.has_overscan_flag() && edid_parser.overscan_flag();
+ display_color_space = GetColorSpaceFromEdid(edid_parser);
} else {
VLOG(1) << "Failed to get EDID blob for connector "
<< info->connector()->connector_id;
@@ -428,7 +430,7 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
display_id, origin, physical_size, type, is_aspect_preserving_scaling,
has_overscan, has_color_correction_matrix, display_color_space,
display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
- product_id, maximum_cursor_size);
+ product_code, year_of_manufacture, maximum_cursor_size);
}
// TODO(rjkroege): Remove in a subsequent CL once Mojo IPC is used everywhere.
@@ -464,7 +466,8 @@ std::vector<DisplaySnapshot_Params> CreateDisplaySnapshotParams(
if (d->native_mode())
p.native_mode = GetDisplayModeParams(*d->native_mode());
- p.product_id = d->product_id();
+ p.product_code = d->product_code();
+ p.year_of_manufacture = d->year_of_manufacture();
p.maximum_cursor_size = d->maximum_cursor_size();
params.push_back(p);
@@ -490,7 +493,8 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
params.is_aspect_preserving_scaling, params.has_overscan,
params.has_color_correction_matrix, params.color_space,
params.display_name, params.sys_path, std::move(modes), params.edid,
- current_mode, native_mode, params.product_id, params.maximum_cursor_size);
+ current_mode, native_mode, params.product_code,
+ params.year_of_manufacture, params.maximum_cursor_size);
}
int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) {
@@ -631,10 +635,8 @@ std::vector<OverlayCheckReturn_Params> CreateParamsFromOverlayStatusList(
return params;
}
-gfx::ColorSpace GetColorSpaceFromEdid(const std::vector<uint8_t>& edid) {
- SkColorSpacePrimaries primaries = {0};
- if (!display::ParseChromaticityCoordinates(edid, &primaries))
- return gfx::ColorSpace();
+gfx::ColorSpace GetColorSpaceFromEdid(const display::EdidParser& edid_parser) {
+ const SkColorSpacePrimaries primaries = edid_parser.primaries();
// Sanity check: primaries should verify By <= Ry <= Gy, Bx <= Rx and Gx <=
// Rx, to guarantee that the R, G and B colors are each in the correct region.
@@ -653,12 +655,25 @@ gfx::ColorSpace GetColorSpaceFromEdid(const std::vector<uint8_t>& edid) {
if (primaries_area_twice < kBT709PrimariesArea)
return gfx::ColorSpace();
+ // Sanity check: https://crbug.com/809909, the blue primary coordinates should
+ // not be too far left/upwards of the expected location (namely [0.15, 0.06]
+ // for sRGB/ BT.709/ Adobe RGB/ DCI-P3, and [0.131, 0.046] for BT.2020).
+ constexpr float kExpectedBluePrimaryX = 0.15f;
+ constexpr float kBluePrimaryXDelta = 0.02f;
+ constexpr float kExpectedBluePrimaryY = 0.06f;
+ constexpr float kBluePrimaryYDelta = 0.031f;
+ const bool is_blue_primary_broken =
+ (std::abs(primaries.fBX - kExpectedBluePrimaryX) > kBluePrimaryXDelta) ||
+ (std::abs(primaries.fBY - kExpectedBluePrimaryY) > kBluePrimaryYDelta);
+ if (is_blue_primary_broken)
+ return gfx::ColorSpace();
+
SkMatrix44 color_space_as_matrix;
if (!primaries.toXYZD50(&color_space_as_matrix))
return gfx::ColorSpace();
- double gamma = 0.0;
- if (!display::ParseGammaValue(edid, &gamma))
+ const double gamma = edid_parser.gamma();
+ if (gamma < 1.0)
return gfx::ColorSpace();
SkColorSpaceTransferFn transfer = {gamma, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.h b/chromium/ui/ozone/platform/drm/common/drm_util.h
index 9a058a78180..6677fe19cfe 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.h
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.h
@@ -21,6 +21,7 @@ typedef struct _drmModeModeInfo drmModeModeInfo;
namespace display {
class DisplayMode;
+class EdidParser;
} // namespace display
namespace gfx {
@@ -119,9 +120,9 @@ OverlayStatusList CreateOverlayStatusListFrom(
std::vector<OverlayCheckReturn_Params> CreateParamsFromOverlayStatusList(
const OverlayStatusList& returns);
-// Parses |edid| to extract a gfx::ColorSpace which will be IsValid() if both
-// gamma and the color primaries were correctly found.
-gfx::ColorSpace GetColorSpaceFromEdid(const std::vector<uint8_t>& edid);
+// Uses |edid_parser| to extract a gfx::ColorSpace which will be IsValid() if
+// both gamma and the color primaries were correctly found.
+gfx::ColorSpace GetColorSpaceFromEdid(const display::EdidParser& edid_parser);
} // namespace ui
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 03dae19b0fc..ec4227e1e31 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -11,6 +11,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/types/display_snapshot.h"
+#include "ui/display/util/edid_parser.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
@@ -93,6 +94,17 @@ const unsigned char kSST210Corrected[] =
"\x30\x31\x20\x54\x69\x44\x69\x67\x61\x74\x0a\x6c\x00\x00\xff\x00"
"\x48\x00\x4b\x34\x41\x54\x30\x30\x32\x38\x0a\x38\x20\x20\xf8\x00";
+// This EDID produces blue primary coordinates too far off the expected point,
+// which would paint blue colors as purple. See https://crbug.com/809909.
+const unsigned char kBrokenBluePrimaries[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x83\x4d\x83\x00\x00\x00\x00"
+ "\x00\x19\x01\x04\x95\x1d\x10\x78\x0a\xee\x25\xa3\x54\x4c\x99\x29"
+ "\x26\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\xd2\x37\x80\xa2\x70\x38\x40\x40\x30\x20"
+ "\x25\x00\x25\xa5\x10\x00\x00\x1a\xa6\x2c\x80\xa2\x70\x38\x40\x40"
+ "\x30\x20\x25\x00\x25\xa5\x10\x00\x00\x1a\x00\x00\x00\xfe\x00\x56"
+ "\x59\x54\x39\x36\x80\x31\x33\x33\x48\x4c\x0a\x20\x00\x00\x00\x00";
+
} // anonymous namespace
bool operator==(const ui::DisplayMode_Params& a,
@@ -114,7 +126,8 @@ bool operator==(const ui::DisplaySnapshot_Params& a,
a.has_current_mode == b.has_current_mode &&
a.current_mode == b.current_mode &&
a.has_native_mode == b.has_native_mode &&
- a.native_mode == b.native_mode && a.product_id == b.product_id &&
+ a.native_mode == b.native_mode && a.product_code == b.product_code &&
+ a.year_of_manufacture == b.year_of_manufacture &&
a.maximum_cursor_size == b.maximum_cursor_size;
}
@@ -146,7 +159,8 @@ void DetailedCompare(const ui::DisplaySnapshot_Params& a,
EXPECT_EQ(a.current_mode, b.current_mode);
EXPECT_EQ(a.has_native_mode, b.has_native_mode);
EXPECT_EQ(a.native_mode, b.native_mode);
- EXPECT_EQ(a.product_id, b.product_id);
+ EXPECT_EQ(a.product_code, b.product_code);
+ EXPECT_EQ(a.year_of_manufacture, b.year_of_manufacture);
EXPECT_EQ(a.maximum_cursor_size, b.maximum_cursor_size);
}
@@ -187,7 +201,8 @@ TEST_F(DrmUtilTest, RoundTripDisplaySnapshot) {
fp.current_mode = MakeDisplay(1.2);
fp.has_native_mode = true;
fp.native_mode = MakeDisplay(1.1);
- fp.product_id = 7;
+ fp.product_code = 7;
+ fp.year_of_manufacture = 1776;
fp.maximum_cursor_size = gfx::Size(103, 44);
sp.display_id = 1002;
@@ -206,7 +221,8 @@ TEST_F(DrmUtilTest, RoundTripDisplaySnapshot) {
sp.has_current_mode = false;
sp.has_native_mode = true;
sp.native_mode = MakeDisplay(500.2);
- sp.product_id = 8;
+ sp.product_code = 8;
+ sp.year_of_manufacture = 2018;
sp.maximum_cursor_size = gfx::Size(500, 44);
ep.display_id = 2002;
@@ -225,7 +241,8 @@ TEST_F(DrmUtilTest, RoundTripDisplaySnapshot) {
ep.has_current_mode = true;
ep.current_mode = MakeDisplay(1000.2);
ep.has_native_mode = false;
- ep.product_id = 9;
+ ep.product_code = 9;
+ ep.year_of_manufacture = 2000;
ep.maximum_cursor_size = gfx::Size(1000, 44);
orig_params.push_back(fp);
@@ -298,8 +315,8 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
hpz32x_toXYZ50_matrix.setRowMajord(hpz32x_toXYZ50_coeffs);
const gfx::ColorSpace hpz32x_color_space = gfx::ColorSpace::CreateCustom(
hpz32x_toXYZ50_matrix, SkColorSpaceTransferFn({2.2, 1, 0, 0, 0, 0, 0}));
- EXPECT_STREQ(hpz32x_color_space.ToString().c_str(),
- GetColorSpaceFromEdid(hpz32x_edid).ToString().c_str());
+ EXPECT_EQ(hpz32x_color_space.ToString(),
+ GetColorSpaceFromEdid(display::EdidParser(hpz32x_edid)).ToString());
const std::vector<uint8_t> samus_edid(kSamus, kSamus + arraysize(kSamus) - 1);
const double samus_toXYZ50_coeffs[] = {0.41211, 0.39743, 0.15468, 0.,
@@ -309,8 +326,8 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
samus_toXYZ50_matrix.setRowMajord(samus_toXYZ50_coeffs);
const gfx::ColorSpace samus_color_space = gfx::ColorSpace::CreateCustom(
samus_toXYZ50_matrix, SkColorSpaceTransferFn({2.5, 1, 0, 0, 0, 0, 0}));
- EXPECT_STREQ(samus_color_space.ToString().c_str(),
- GetColorSpaceFromEdid(samus_edid).ToString().c_str());
+ EXPECT_EQ(samus_color_space.ToString(),
+ GetColorSpaceFromEdid(display::EdidParser(samus_edid)).ToString());
const std::vector<uint8_t> eve_edid(kEve, kEve + arraysize(kEve) - 1);
const double eve_toXYZ50_coeffs[] = {0.444601, 0.377972, 0.141646, 0.,
@@ -320,37 +337,47 @@ TEST_F(DrmUtilTest, GetColorSpaceFromEdid) {
eve_toXYZ50_matrix.setRowMajord(eve_toXYZ50_coeffs);
const gfx::ColorSpace eve_color_space = gfx::ColorSpace::CreateCustom(
eve_toXYZ50_matrix, SkColorSpaceTransferFn({2.2, 1, 0, 0, 0, 0, 0}));
- EXPECT_STREQ(eve_color_space.ToString().c_str(),
- GetColorSpaceFromEdid(eve_edid).ToString().c_str());
+ EXPECT_EQ(eve_color_space.ToString(),
+ GetColorSpaceFromEdid(display::EdidParser(eve_edid)).ToString());
const std::vector<uint8_t> no_gamma_edid(
kEdidWithNoGamma, kEdidWithNoGamma + arraysize(kEdidWithNoGamma) - 1);
const gfx::ColorSpace no_gamma_color_space =
- GetColorSpaceFromEdid(no_gamma_edid);
+ GetColorSpaceFromEdid(display::EdidParser(no_gamma_edid));
EXPECT_FALSE(no_gamma_color_space.IsValid());
}
TEST_F(DrmUtilTest, GetInvalidColorSpaceFromEdid) {
const std::vector<uint8_t> empty_edid;
- EXPECT_EQ(gfx::ColorSpace(), GetColorSpaceFromEdid(empty_edid));
+ EXPECT_EQ(gfx::ColorSpace(),
+ GetColorSpaceFromEdid(display::EdidParser(empty_edid)));
const std::vector<uint8_t> invalid_edid(
kInvalidEdid, kInvalidEdid + arraysize(kInvalidEdid) - 1);
const gfx::ColorSpace invalid_color_space =
- GetColorSpaceFromEdid(invalid_edid);
+ GetColorSpaceFromEdid(display::EdidParser(invalid_edid));
EXPECT_FALSE(invalid_color_space.IsValid());
const std::vector<uint8_t> sst210_edid(kSST210,
kSST210 + arraysize(kSST210) - 1);
- const gfx::ColorSpace sst210_color_space = GetColorSpaceFromEdid(sst210_edid);
+ const gfx::ColorSpace sst210_color_space =
+ GetColorSpaceFromEdid(display::EdidParser(sst210_edid));
EXPECT_FALSE(sst210_color_space.IsValid()) << sst210_color_space.ToString();
const std::vector<uint8_t> sst210_edid_2(
kSST210Corrected, kSST210Corrected + arraysize(kSST210Corrected) - 1);
const gfx::ColorSpace sst210_color_space_2 =
- GetColorSpaceFromEdid(sst210_edid_2);
+ GetColorSpaceFromEdid(display::EdidParser(sst210_edid_2));
EXPECT_FALSE(sst210_color_space_2.IsValid())
<< sst210_color_space_2.ToString();
+
+ const std::vector<uint8_t> broken_blue_edid(
+ kBrokenBluePrimaries,
+ kBrokenBluePrimaries + arraysize(kBrokenBluePrimaries) - 1);
+ const gfx::ColorSpace broken_blue_color_space =
+ GetColorSpaceFromEdid(display::EdidParser(broken_blue_edid));
+ EXPECT_FALSE(broken_blue_color_space.IsValid())
+ << broken_blue_color_space.ToString();
}
TEST_F(DrmUtilTest, TestDisplayModesExtraction) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
index 88456854b97..fdf87224eda 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -44,11 +44,11 @@ CrtcController::~CrtcController() {
}
bool CrtcController::Modeset(const OverlayPlane& plane, drmModeModeInfo mode) {
- if (!drm_->SetCrtc(crtc_, plane.buffer->GetFramebufferId(),
+ if (!drm_->SetCrtc(crtc_, plane.buffer->GetOpaqueFramebufferId(),
std::vector<uint32_t>(1, connector_), &mode)) {
PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_
<< " connector=" << connector_
- << " framebuffer_id=" << plane.buffer->GetFramebufferId()
+ << " framebuffer_id=" << plane.buffer->GetOpaqueFramebufferId()
<< " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
<< mode.vrefresh;
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
index 9fd0bd15bc8..b3ffc96902d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/free_deleter.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_for_io.h"
#include "base/posix/safe_strerror.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -289,7 +290,7 @@ class DrmDevice::PageFlipManager {
DISALLOW_COPY_AND_ASSIGN(PageFlipManager);
};
-class DrmDevice::IOWatcher : public base::MessagePumpLibevent::Watcher {
+class DrmDevice::IOWatcher : public base::MessagePumpLibevent::FdWatcher {
public:
IOWatcher(int fd, DrmDevice::PageFlipManager* page_flip_manager)
: page_flip_manager_(page_flip_manager), controller_(FROM_HERE), fd_(fd) {
@@ -302,7 +303,7 @@ class DrmDevice::IOWatcher : public base::MessagePumpLibevent::Watcher {
void Register() {
DCHECK(base::MessageLoopForIO::IsCurrent());
base::MessageLoopForIO::current()->WatchFileDescriptor(
- fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this);
+ fd_, true, base::MessagePumpForIO::WATCH_READ, &controller_, this);
}
void Unregister() {
@@ -310,7 +311,7 @@ class DrmDevice::IOWatcher : public base::MessagePumpLibevent::Watcher {
controller_.StopWatchingFileDescriptor();
}
- // base::MessagePumpLibevent::Watcher overrides:
+ // base::MessagePumpLibevent::FdWatcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override {
DCHECK(base::MessageLoopForIO::IsCurrent());
TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd);
@@ -324,7 +325,7 @@ class DrmDevice::IOWatcher : public base::MessagePumpLibevent::Watcher {
DrmDevice::PageFlipManager* page_flip_manager_;
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
int fd_;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 07d013b97c3..ce85361b01e 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -7,7 +7,6 @@
#include <xf86drmMode.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
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 d07f5760ed1..a1cd5650a7c 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
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/memory/ptr_util.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
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 15d5bae1977..d0a82568e4a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -82,7 +82,7 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip(
OverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform,
params[i].display_rect, params[i].crop_rect,
- base::kInvalidPlatformFile);
+ /* enable_blend */ true, base::kInvalidPlatformFile);
test_list.push_back(plane);
if (buffer && controller->TestPageFlip(test_list)) {
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 0328b0cc82c..3b3642b8d88 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
@@ -138,7 +138,7 @@ void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
params.buffer_size);
ui::OverlayPlane plane(std::move(scanout_buffer), params.plane_z_order,
params.transform, params.display_rect,
- params.crop_rect, base::kInvalidPlatformFile);
+ params.crop_rect, true, base::kInvalidPlatformFile);
plane_list_.push_back(plane);
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index 566de8b0b67..6e187761ea9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
@@ -204,7 +203,7 @@ void DrmThread::SchedulePageFlip(gfx::AcceleratedWidget widget,
drm_device->plane_manager()->RequestPlanesReadyCallback(
planes, base::BindOnce(&DrmThread::OnPlanesReadyForPageFlip,
weak_ptr_factory_.GetWeakPtr(), widget, planes,
- base::Passed(&callback)));
+ std::move(callback)));
}
void DrmThread::OnPlanesReadyForPageFlip(
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
index 6e1d4a749e3..842ed61ff2c 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
@@ -65,23 +65,23 @@ bool DrmThreadMessageProxy::OnMessageReceived(const IPC::Message& message) {
void DrmThreadMessageProxy::OnCreateWindow(gfx::AcceleratedWidget widget) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DrmThread::CreateWindow,
- base::Unretained(drm_thread_), widget));
+ FROM_HERE, base::BindOnce(&DrmThread::CreateWindow,
+ base::Unretained(drm_thread_), widget));
}
void DrmThreadMessageProxy::OnDestroyWindow(gfx::AcceleratedWidget widget) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DrmThread::DestroyWindow,
- base::Unretained(drm_thread_), widget));
+ FROM_HERE, base::BindOnce(&DrmThread::DestroyWindow,
+ base::Unretained(drm_thread_), widget));
}
void DrmThreadMessageProxy::OnWindowBoundsChanged(gfx::AcceleratedWidget widget,
const gfx::Rect& bounds) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DrmThread::SetWindowBounds,
- base::Unretained(drm_thread_), widget, bounds));
+ FROM_HERE, base::BindOnce(&DrmThread::SetWindowBounds,
+ base::Unretained(drm_thread_), widget, bounds));
}
void DrmThreadMessageProxy::OnCursorSet(gfx::AcceleratedWidget widget,
@@ -91,16 +91,17 @@ void DrmThreadMessageProxy::OnCursorSet(gfx::AcceleratedWidget widget,
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&DrmThread::SetCursor, base::Unretained(drm_thread_), widget,
- bitmaps, location, frame_delay_ms));
+ base::BindOnce(&DrmThread::SetCursor, base::Unretained(drm_thread_),
+ widget, bitmaps, location, frame_delay_ms));
}
void DrmThreadMessageProxy::OnCursorMove(gfx::AcceleratedWidget widget,
const gfx::Point& location) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DrmThread::MoveCursor,
- base::Unretained(drm_thread_), widget, location));
+ FROM_HERE,
+ base::BindOnce(&DrmThread::MoveCursor, base::Unretained(drm_thread_),
+ widget, location));
}
void DrmThreadMessageProxy::OnCheckOverlayCapabilities(
@@ -191,15 +192,15 @@ void DrmThreadMessageProxy::OnAddGraphicsDevice(
base::File file(fd.fd);
drm_thread_->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&DrmThread::AddGraphicsDevice, base::Unretained(drm_thread_),
- path, Passed(&file)));
+ base::BindOnce(&DrmThread::AddGraphicsDevice,
+ base::Unretained(drm_thread_), path, std::move(file)));
}
void DrmThreadMessageProxy::OnRemoveGraphicsDevice(const base::FilePath& path) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DrmThread::RemoveGraphicsDevice,
- base::Unretained(drm_thread_), path));
+ FROM_HERE, base::BindOnce(&DrmThread::RemoveGraphicsDevice,
+ base::Unretained(drm_thread_), path));
}
void DrmThreadMessageProxy::OnGetHDCPState(int64_t display_id) {
@@ -232,9 +233,9 @@ void DrmThreadMessageProxy::OnSetColorCorrection(
const std::vector<float>& correction_matrix) {
DCHECK(drm_thread_->IsRunning());
drm_thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DrmThread::SetColorCorrection, base::Unretained(drm_thread_),
- id, degamma_lut, gamma_lut, correction_matrix));
+ FROM_HERE, base::BindOnce(&DrmThread::SetColorCorrection,
+ base::Unretained(drm_thread_), id, degamma_lut,
+ gamma_lut, correction_matrix));
}
void DrmThreadMessageProxy::OnCheckOverlayCapabilitiesCallback(
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 2bad52ddd44..fe6c4b3affa 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -5,7 +5,6 @@
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
#include "ui/ozone/platform/drm/gpu/gbm_buffer.h"
@@ -76,8 +75,8 @@ void DrmThreadProxy::AddBindingCursorDevice(
ozone::mojom::DeviceCursorRequest request) {
drm_thread_.task_runner()->PostTask(
FROM_HERE,
- base::Bind(&DrmThread::AddBindingCursorDevice,
- base::Unretained(&drm_thread_), base::Passed(&request)));
+ base::BindOnce(&DrmThread::AddBindingCursorDevice,
+ base::Unretained(&drm_thread_), std::move(request)));
}
void DrmThreadProxy::AddBindingDrmDevice(
@@ -87,8 +86,8 @@ void DrmThreadProxy::AddBindingDrmDevice(
drm_thread_.task_runner()->PostTask(
FROM_HERE,
- base::Bind(&DrmThread::AddBindingDrmDevice,
- base::Unretained(&drm_thread_), base::Passed(&request)));
+ base::BindOnce(&DrmThread::AddBindingDrmDevice,
+ base::Unretained(&drm_thread_), std::move(request)));
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
index 51d18556c01..6deff4440b2 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -8,7 +8,6 @@
#include <stdint.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
index cd41e064885..f5f882a7958 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
@@ -30,9 +30,9 @@ void DrmWindowProxy::SchedulePageFlip(const std::vector<OverlayPlane>& planes,
void DrmWindowProxy::GetVSyncParameters(
const gfx::VSyncProvider::UpdateVSyncCallback& callback) {
drm_thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DrmThread::GetVSyncParameters, base::Unretained(drm_thread_),
- widget_, CreateSafeCallback(callback)));
+ FROM_HERE, base::BindOnce(&DrmThread::GetVSyncParameters,
+ base::Unretained(drm_thread_), widget_,
+ CreateSafeCallback(callback)));
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
index 4faa63288cc..40a207ec1c3 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
@@ -183,7 +183,7 @@ TEST_F(DrmWindowTest, CheckCallbackOnFailedSwap) {
// Window was re-sized, so the expectation is to re-create the buffers first.
window->SchedulePageFlip(
std::vector<ui::OverlayPlane>(1, ui::OverlayPlane(plane)),
- base::Bind(&DrmWindowTest::OnSwapBuffers, base::Unretained(this)));
+ base::BindOnce(&DrmWindowTest::OnSwapBuffers, base::Unretained(this)));
EXPECT_EQ(1, on_swap_buffers_count_);
EXPECT_EQ(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS,
last_swap_buffers_result_);
@@ -191,7 +191,7 @@ TEST_F(DrmWindowTest, CheckCallbackOnFailedSwap) {
window->SchedulePageFlip(
std::vector<ui::OverlayPlane>(1, ui::OverlayPlane(plane)),
- base::Bind(&DrmWindowTest::OnSwapBuffers, base::Unretained(this)));
+ base::BindOnce(&DrmWindowTest::OnSwapBuffers, base::Unretained(this)));
EXPECT_EQ(2, on_swap_buffers_count_);
EXPECT_EQ(gfx::SwapResult::SWAP_FAILED, last_swap_buffers_result_);
EXPECT_EQ(gfx::PresentationFeedback(), last_presentation_feedback_);
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index 17948261354..19a26ada002 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -385,11 +385,12 @@ bool GbmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
DCHECK(buffer_->GetFlags() & GBM_BO_USE_SCANOUT);
surface_manager_->GetSurface(widget)->QueueOverlayPlane(
OverlayPlane(buffer_, plane_z_order, plane_transform, display_bounds,
- crop_rect, base::kInvalidPlatformFile));
+ crop_rect, enable_blend, base::kInvalidPlatformFile));
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.h b/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.h
index 984e7df6afd..8a5573db3e4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -121,7 +121,8 @@ class GbmPixmap : public gfx::NativePixmap {
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
gfx::NativePixmapHandle ExportHandle() override;
scoped_refptr<GbmBuffer> buffer() { return buffer_; }
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface.cc
index ac50b648d41..56c05a954a5 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface.cc
@@ -65,7 +65,7 @@ void GbmSurface::SwapBuffersAsync(
const PresentationCallback& presentation_callback) {
if (!images_[current_surface_]->ScheduleOverlayPlane(
widget(), 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(GetSize()), gfx::RectF(1, 1))) {
+ gfx::Rect(GetSize()), gfx::RectF(1, 1), /* enable_blend */ false)) {
completion_callback.Run(gfx::SwapResult::SWAP_FAILED);
// Notify the caller, the buffer is never presented on a screen.
presentation_callback.Run(gfx::PresentationFeedback());
@@ -136,7 +136,7 @@ bool GbmSurface::CreatePixmaps() {
if (!pixmap)
return false;
scoped_refptr<gl::GLImageNativePixmap> image =
- new gl::GLImageNativePixmap(GetSize(), GL_RGB);
+ new gl::GLImageNativePixmap(GetSize(), GL_BGRA_EXT);
if (!image->Initialize(pixmap.get(),
display::DisplaySnapshot::PrimaryFormat()))
return false;
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 ca8a5206071..4fdef17f041 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "third_party/khronos/EGL/egl.h"
#include "ui/gfx/buffer_format_util.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index fab047e68ca..f067067795a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/presentation_feedback.h"
@@ -68,9 +67,10 @@ bool GbmSurfaceless::ScheduleOverlayPlane(int z_order,
gfx::OverlayTransform transform,
gl::GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) {
- unsubmitted_frames_.back()->overlays.push_back(
- gl::GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect));
+ const gfx::RectF& crop_rect,
+ bool enable_blend) {
+ unsubmitted_frames_.back()->overlays.push_back(gl::GLSurfaceOverlay(
+ z_order, transform, image, bounds_rect, crop_rect, enable_blend));
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 32cf0e8e863..71c3022e384 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -41,7 +41,8 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
gfx::OverlayTransform transform,
gl::GLImage* image,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override;
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override;
bool IsOffscreen() override;
gfx::VSyncProvider* GetVSyncProvider() override;
bool SupportsPresentationCallback() override;
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 de661e983a7..aa68355c3a2 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -10,7 +10,6 @@
#include <utility>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/geometry/point.h"
@@ -117,11 +116,6 @@ bool HardwareDisplayController::ActualSchedulePageFlip(
[](const OverlayPlane& l, const OverlayPlane& r) {
return l.z_order < r.z_order;
});
- if (pending_planes.front().z_order < 0) {
- std::move(callback).Run(gfx::SwapResult::SWAP_FAILED,
- gfx::PresentationFeedback());
- return false;
- }
scoped_refptr<PageFlipRequest> page_flip_request =
new PageFlipRequest(crtc_controllers_.size(), std::move(callback));
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 afc1acf0d57..d31581b51a8 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
@@ -107,8 +107,8 @@ TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_TRUE(plane1.buffer->HasOneRef());
EXPECT_FALSE(plane2.buffer->HasOneRef());
@@ -144,8 +144,8 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
planes.clear();
@@ -162,7 +162,7 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
ui::OverlayPlane plane2(
scoped_refptr<ui::ScanoutBuffer>(new ui::MockScanoutBuffer(kOverlaySize)),
1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kOverlaySize),
- gfx::RectF(kDefaultModeSizeF), base::kInvalidPlatformFile);
+ gfx::RectF(kDefaultModeSizeF), true, base::kInvalidPlatformFile);
EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
@@ -171,8 +171,8 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
planes.push_back(plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -187,7 +187,7 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
ui::OverlayPlane plane2(
scoped_refptr<ui::ScanoutBuffer>(new ui::MockScanoutBuffer(kOverlaySize)),
1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kOverlaySize),
- gfx::RectF(kDefaultModeSizeF), base::kInvalidPlatformFile);
+ gfx::RectF(kDefaultModeSizeF), true, base::kInvalidPlatformFile);
EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
@@ -196,8 +196,8 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
planes.push_back(plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
// A test call shouldn't cause new flips, but should succeed.
EXPECT_TRUE(controller_->TestPageFlip(planes));
@@ -209,8 +209,8 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
// Regular flips should continue on normally.
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(2, page_flips_);
@@ -218,7 +218,7 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
EXPECT_EQ(2, drm_->get_overlay_flip_call_count());
}
-TEST_F(HardwareDisplayControllerTest, RejectUnderlays) {
+TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) {
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(kDefaultModeSize)),
base::kInvalidPlatformFile);
@@ -226,7 +226,7 @@ TEST_F(HardwareDisplayControllerTest, RejectUnderlays) {
scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(kDefaultModeSize)),
-1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kDefaultModeSize),
- gfx::RectF(kDefaultModeSizeF), base::kInvalidPlatformFile);
+ gfx::RectF(kDefaultModeSizeF), true, base::kInvalidPlatformFile);
EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
@@ -235,9 +235,10 @@ TEST_F(HardwareDisplayControllerTest, RejectUnderlays) {
planes.push_back(plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
- EXPECT_EQ(gfx::SwapResult::SWAP_FAILED, last_swap_result_);
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
+ drm_->RunCallbacks();
+ EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
}
@@ -257,8 +258,8 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -274,8 +275,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -297,8 +298,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
// Check that controller doesn't affect the state of removed plane in
// subsequent page flip.
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -314,8 +315,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -346,8 +347,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -364,8 +365,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
hdc_controller.reset(new ui::HardwareDisplayController(
controller_->RemoveCrtc(drm_, kPrimaryCrtc), controller_->origin()));
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(2, page_flips_);
@@ -378,8 +379,8 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
primary_crtc_plane->set_in_use(false);
primary_crtc_plane->set_owning_crtc(0);
hdc_controller->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(3, page_flips_);
@@ -395,8 +396,8 @@ TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
drm_->RunCallbacks();
@@ -414,8 +415,8 @@ TEST_F(HardwareDisplayControllerTest, FailPageFlipping) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_FAILED, last_swap_result_);
@@ -427,13 +428,13 @@ TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlane) {
new ui::MockScanoutBuffer(kDefaultModeSize)),
1, gfx::OVERLAY_TRANSFORM_NONE,
gfx::Rect(kDefaultModeSize), gfx::RectF(0, 0, 1, 1),
- base::kInvalidPlatformFile);
+ true, base::kInvalidPlatformFile);
EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -448,8 +449,8 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
controller_->AddCrtc(std::unique_ptr<ui::CrtcController>(
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
@@ -467,8 +468,8 @@ TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
std::vector<ui::OverlayPlane> planes =
std::vector<ui::OverlayPlane>(1, plane1);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
controller_->RemoveCrtc(drm_, kPrimaryCrtc);
@@ -486,15 +487,15 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
ui::OverlayPlane plane2(new ui::MockScanoutBuffer(kOverlaySize), 1,
gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kOverlaySize),
- gfx::RectF(kDefaultModeSizeF),
+ gfx::RectF(kDefaultModeSizeF), true,
base::kInvalidPlatformFile);
std::vector<ui::OverlayPlane> planes;
planes.push_back(plane1);
planes.push_back(plane2);
controller_->SchedulePageFlip(
- planes, base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
- base::Unretained(this)));
+ planes, base::BindOnce(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this)));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
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 bf7ddde34f3..952c6f93e0d 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
@@ -25,13 +25,13 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
HardwareDisplayPlaneAtomic(uint32_t plane_id, uint32_t possible_crtcs);
~HardwareDisplayPlaneAtomic() override;
- bool SetPlaneData(drmModeAtomicReq* property_set,
- uint32_t crtc_id,
- uint32_t framebuffer,
- const gfx::Rect& crtc_rect,
- const gfx::Rect& src_rect,
- const gfx::OverlayTransform transform,
- int in_fence_fd);
+ virtual bool SetPlaneData(drmModeAtomicReq* property_set,
+ uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect,
+ const gfx::OverlayTransform transform,
+ int in_fence_fd);
void set_crtc(CrtcController* crtc) { crtc_ = crtc; }
CrtcController* crtc() const { return crtc_; }
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 b74520781ae..42446c9316d 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
@@ -214,7 +214,10 @@ bool HardwareDisplayPlaneManager::IsCompatible(HardwareDisplayPlane* plane,
if (!plane->CanUseForCrtc(crtc_index))
return false;
- if (!plane->IsSupportedFormat(overlay.buffer->GetFramebufferPixelFormat()))
+ const uint32_t format = overlay.enable_blend ?
+ overlay.buffer->GetFramebufferPixelFormat() :
+ overlay.buffer->GetOpaqueFramebufferPixelFormat();
+ if (!plane->IsSupportedFormat(format))
return false;
// TODO(kalyank): We should check for z-order and any needed transformation
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 f49d7cbd611..134c40ee9d9 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
@@ -137,9 +137,9 @@ class HardwareDisplayPlaneManager {
// Returns true if |plane| can support |overlay| and compatible with
// |crtc_index|.
- bool IsCompatible(HardwareDisplayPlane* plane,
- const OverlayPlane& overlay,
- uint32_t crtc_index) const;
+ virtual bool IsCompatible(HardwareDisplayPlane* plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_index) const;
void ResetCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
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 febc9945b23..a2b7170f630 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
@@ -142,7 +142,7 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
CrtcController* crtc) {
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(hw_plane);
- uint32_t framebuffer_id = overlay.z_order
+ uint32_t framebuffer_id = overlay.enable_blend
? overlay.buffer->GetFramebufferId()
: overlay.buffer->GetOpaqueFramebufferId();
if (!atomic_plane->SetPlaneData(plane_list->atomic_property_set.get(),
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
index 7dd8b19f94b..46619c52f9a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -27,8 +27,6 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
void RequestPlanesReadyCallback(const OverlayPlaneList& planes,
base::OnceClosure callback) override;
-
- private:
bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
HardwareDisplayPlane* hw_plane,
const OverlayPlane& overlay,
@@ -36,6 +34,7 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
const gfx::Rect& src_rect,
CrtcController* crtc) override;
+ private:
std::unique_ptr<HardwareDisplayPlane> CreatePlane(
uint32_t plane_id,
uint32_t possible_crtcs) override;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
index 8aaf4e280d2..a87020d2c4d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
@@ -167,10 +167,23 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData(
} else {
plane_list->legacy_page_flips.back().planes.push_back(
HardwareDisplayPlaneList::PageFlipInfo::Plane(
- hw_plane->plane_id(), overlay.buffer->GetFramebufferId(),
+ hw_plane->plane_id(), overlay.buffer->GetOpaqueFramebufferId(),
overlay.display_bounds, src_rect));
}
return true;
}
+bool HardwareDisplayPlaneManagerLegacy::IsCompatible(
+ HardwareDisplayPlane* plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_index) const {
+ if (!plane->CanUseForCrtc(crtc_index))
+ return false;
+
+ // When using legacy kms we always scanout only one plane (the primary),
+ // and we always use the opaque fb. Refer to SetPlaneData above.
+ const uint32_t format = overlay.buffer->GetOpaqueFramebufferPixelFormat();
+ return plane->IsSupportedFormat(format);
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
index 3f492ca1d37..db1d78a4b07 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
@@ -35,6 +35,9 @@ class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager {
uint32_t crtc_id,
const gfx::Rect& src_rect,
CrtcController* crtc) override;
+ bool IsCompatible(HardwareDisplayPlane* plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_index) const override;
private:
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerLegacy);
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 3c5f7146d96..46f2d563fde 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
@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/fake_plane_info.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
@@ -362,4 +363,44 @@ TEST_F(HardwareDisplayPlaneManagerPlanesReadyTest,
EXPECT_TRUE(callback_called);
}
+class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic {
+ public:
+ HardwareDisplayPlaneAtomicMock() : ui::HardwareDisplayPlaneAtomic(0, ~0) {}
+ ~HardwareDisplayPlaneAtomicMock() override {}
+
+ bool SetPlaneData(drmModeAtomicReq* property_set,
+ uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect,
+ const gfx::OverlayTransform transform,
+ int in_fence_fd) override {
+ framebuffer_ = framebuffer;
+ return true;
+ }
+ uint32_t framebuffer() const { return framebuffer_; }
+
+ private:
+ uint32_t framebuffer_ = 0;
+};
+
+TEST(HardwareDisplayPlaneManagerAtomic, EnableBlend) {
+ auto plane_manager =
+ std::make_unique<ui::HardwareDisplayPlaneManagerAtomic>();
+ ui::HardwareDisplayPlaneList plane_list;
+ HardwareDisplayPlaneAtomicMock hw_plane;
+ scoped_refptr<ui::ScanoutBuffer> buffer =
+ new ui::MockScanoutBuffer(kDefaultBufferSize);
+ ui::OverlayPlane overlay(buffer, base::kInvalidPlatformFile);
+ overlay.enable_blend = true;
+ plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(),
+ nullptr);
+ EXPECT_EQ(hw_plane.framebuffer(), buffer->GetFramebufferId());
+
+ overlay.enable_blend = false;
+ plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(),
+ nullptr);
+ EXPECT_EQ(hw_plane.framebuffer(), buffer->GetOpaqueFramebufferId());
+}
+
} // namespace
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc b/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
index fd15615ecd6..1230e86011f 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
@@ -21,6 +21,7 @@ MockScanoutBuffer::MockScanoutBuffer(const gfx::Size& size,
format_(format),
modifier_(modifier),
id_(g_current_framebuffer_id++),
+ opaque_id_(g_current_framebuffer_id++),
drm_(drm) {}
MockScanoutBuffer::~MockScanoutBuffer() {}
@@ -30,7 +31,7 @@ uint32_t MockScanoutBuffer::GetFramebufferId() const {
}
uint32_t MockScanoutBuffer::GetOpaqueFramebufferId() const {
- return 2;
+ return opaque_id_;
}
uint32_t MockScanoutBuffer::GetHandle() const {
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h b/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
index 33f5977d776..cbeb256d5b4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
@@ -38,6 +38,7 @@ class MockScanoutBuffer : public ScanoutBuffer {
uint32_t format_;
uint64_t modifier_;
uint32_t id_;
+ uint32_t opaque_id_;
scoped_refptr<DrmDevice> drm_;
DISALLOW_COPY_AND_ASSIGN(MockScanoutBuffer);
diff --git a/chromium/ui/ozone/platform/drm/gpu/overlay_plane.cc b/chromium/ui/ozone/platform/drm/gpu/overlay_plane.cc
index 8135647550e..8cf1be09bf9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/overlay_plane.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/overlay_plane.cc
@@ -16,6 +16,7 @@ OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
plane_transform(gfx::OVERLAY_TRANSFORM_NONE),
display_bounds(gfx::Point(), buffer->GetSize()),
crop_rect(0, 0, 1, 1),
+ enable_blend(false),
fence_fd(fence_fd) {}
OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
@@ -23,12 +24,14 @@ OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect,
+ bool enable_blend,
int fence_fd)
: buffer(buffer),
z_order(z_order),
plane_transform(plane_transform),
display_bounds(display_bounds),
crop_rect(crop_rect),
+ enable_blend(enable_blend),
fence_fd(fence_fd) {}
OverlayPlane::OverlayPlane(const OverlayPlane& other) = default;
diff --git a/chromium/ui/ozone/platform/drm/gpu/overlay_plane.h b/chromium/ui/ozone/platform/drm/gpu/overlay_plane.h
index 4bfb9b4738c..31fa65d49e6 100644
--- a/chromium/ui/ozone/platform/drm/gpu/overlay_plane.h
+++ b/chromium/ui/ozone/platform/drm/gpu/overlay_plane.h
@@ -30,6 +30,7 @@ struct OverlayPlane {
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect,
+ bool enable_blend,
int fence_fd);
OverlayPlane(const OverlayPlane& other);
@@ -45,6 +46,7 @@ struct OverlayPlane {
gfx::OverlayTransform plane_transform;
gfx::Rect display_bounds;
gfx::RectF crop_rect;
+ bool enable_blend;
int fence_fd;
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
index 60bc23f75ea..863e96531c4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
@@ -24,7 +24,7 @@ void PostSyncTask(
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
bool success = task_runner->PostTask(
- FROM_HERE, base::Bind(OnRunPostedTaskAndSignal, callback, &wait));
+ FROM_HERE, base::BindOnce(OnRunPostedTaskAndSignal, callback, &wait));
if (success)
wait.Wait();
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
index 086709c9a01..a1393ef3dfa 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
@@ -19,7 +19,7 @@ void PostAsyncTask(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const base::Callback<void(Args...)>& callback,
Args... args) {
- task_runner->PostTask(FROM_HERE, base::Bind(callback, args...));
+ task_runner->PostTask(FROM_HERE, base::BindOnce(callback, args...));
}
template <typename... Args>
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
index 46e5223c7d6..5dbc2853518 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
@@ -29,8 +29,8 @@ class ProxyHelpersTest : public testing::Test {
EXPECT_TRUE(drm_checker_.CalledOnValidThread());
message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ProxyHelpersTest::QuitFunctionCallback,
- base::Unretained(this), 8));
+ FROM_HERE, base::BindOnce(&ProxyHelpersTest::QuitFunctionCallback,
+ base::Unretained(this), 8));
}
// QuitFunctionCallback runs on the main thread.
@@ -106,7 +106,7 @@ TEST_F(ProxyHelpersTest, PostTask) {
// Binds the thread checker on the drm thread.
drm_thread_->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&ProxyHelpersTest::SetDrmChecker, base::Unretained(this)));
+ base::BindOnce(&ProxyHelpersTest::SetDrmChecker, base::Unretained(this)));
// Test passing a type by value.
auto value_callback = base::BindOnce(&ProxyHelpersTest::ValueTypeCallback,
@@ -147,8 +147,8 @@ TEST_F(ProxyHelpersTest, PostTask) {
// Shutdown the RunLoop.
drm_thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ProxyHelpersTest::QuitFunction, base::Unretained(this), 42));
+ FROM_HERE, base::BindOnce(&ProxyHelpersTest::QuitFunction,
+ base::Unretained(this), 42));
run_loop_.Run();
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
index 87b2abc6f37..e8e477733e4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "base/files/platform_file.h"
-#include "base/memory/ptr_util.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/gfx/geometry/point.h"
@@ -32,9 +31,9 @@ namespace {
void FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
HardwareDisplayController* controller,
ScanoutBuffer* buffer) {
- DrmConsoleBuffer modeset_buffer(drm, buffer->GetFramebufferId());
+ DrmConsoleBuffer modeset_buffer(drm, buffer->GetOpaqueFramebufferId());
if (!modeset_buffer.Initialize()) {
- VLOG(2) << "Failed to grab framebuffer " << buffer->GetFramebufferId();
+ VLOG(2) << "Failed to grab framebuffer " << buffer->GetOpaqueFramebufferId();
return;
}
@@ -378,7 +377,8 @@ OverlayPlane ScreenManager::GetModesetBuffer(
if (!buffer) {
LOG(ERROR) << "Failed to create scanout buffer";
return OverlayPlane(nullptr, 0, gfx::OVERLAY_TRANSFORM_INVALID, gfx::Rect(),
- gfx::RectF(), base::kInvalidPlatformFile);
+ gfx::RectF(), /* enable_blend */ true,
+ base::kInvalidPlatformFile);
}
FillModesetBuffer(drm, controller, buffer.get());
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 2fe14daad7d..a50a0ac275a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -511,7 +511,7 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
kDefaultMode);
- EXPECT_EQ(buffer->GetFramebufferId(), drm_->current_framebuffer());
+ EXPECT_EQ(buffer->GetOpaqueFramebufferId(), drm_->current_framebuffer());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
index 0042294556f..8ffc06b4c05 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -226,6 +226,9 @@ void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) {
gfx::PointF(confined_bounds_.right() - 1, confined_bounds_.bottom() - 1));
location_ = clamped_location;
+#if defined(OS_CHROMEOS)
+ ui::CursorController::GetInstance()->SetCursorLocation(location_);
+#endif
}
void DrmCursor::SendCursorShowLocked() {
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
index 9868a4e3719..d486445a005 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
@@ -56,7 +55,7 @@ void DrmDisplayHost::Configure(const display::DisplayMode* mode,
void DrmDisplayHost::OnDisplayConfigured(bool status) {
if (!configure_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(configure_callback_, status));
+ FROM_HERE, base::BindOnce(configure_callback_, status));
} else {
LOG(ERROR) << "Got unexpected event for display "
<< snapshot_->display_id();
@@ -76,7 +75,7 @@ void DrmDisplayHost::OnHDCPStateReceived(bool status,
display::HDCPState state) {
if (!get_hdcp_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(get_hdcp_callback_, status, state));
+ FROM_HERE, base::BindOnce(get_hdcp_callback_, status, state));
} else {
LOG(ERROR) << "Got unexpected event for display "
<< snapshot_->display_id();
@@ -96,7 +95,7 @@ void DrmDisplayHost::SetHDCPState(
void DrmDisplayHost::OnHDCPStateUpdated(bool status) {
if (!set_hdcp_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(set_hdcp_callback_, status));
+ FROM_HERE, base::BindOnce(set_hdcp_callback_, status));
} else {
LOG(ERROR) << "Got unexpected event for display "
<< snapshot_->display_id();
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 c3f28c7b473..31967c98427 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
@@ -12,7 +12,6 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_restrictions.h"
@@ -60,9 +59,9 @@ void OpenDeviceAsync(const base::FilePath& device_path,
std::unique_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
handle->Initialize(device_path, sys_path);
- reply_runner->PostTask(FROM_HERE,
- base::Bind(callback, device_path, sys_path,
- base::Passed(std::move(handle))));
+ reply_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(callback, device_path, sys_path, std::move(handle)));
}
base::FilePath GetPrimaryDisplayCardPath() {
@@ -253,18 +252,19 @@ void DrmDisplayHostManager::ProcessEvent() {
FROM_HERE,
{base::MayBlock(),
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
- base::Bind(&OpenDeviceAsync, event.path,
- base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
- weak_ptr_factory_.GetWeakPtr())));
+ base::BindOnce(
+ &OpenDeviceAsync, event.path,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr())));
task_pending_ = true;
}
break;
case DeviceEvent::CHANGE:
task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr()));
break;
case DeviceEvent::REMOVE:
DCHECK(event.path != primary_graphics_card_path_)
@@ -273,8 +273,8 @@ void DrmDisplayHostManager::ProcessEvent() {
if (it != drm_devices_.end()) {
task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
- weak_ptr_factory_.GetWeakPtr(), it->second));
+ base::BindOnce(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr(), it->second));
drm_devices_.erase(it);
}
break;
@@ -321,7 +321,7 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() {
MapDevPathToSysPath(primary_graphics_card_path_);
if (!handle) {
- handle.reset(new DrmDeviceHandle());
+ handle = std::make_unique<DrmDeviceHandle>();
if (!handle->Initialize(primary_graphics_card_path_,
drm_devices_[primary_graphics_card_path_]))
LOG(FATAL) << "Failed to open primary graphics card";
@@ -330,8 +330,10 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() {
// Send the primary device first since this is used to initialize graphics
// state.
- proxy_->GpuAddGraphicsDevice(drm_devices_[primary_graphics_card_path_],
- handle->PassFD());
+ if (!proxy_->GpuAddGraphicsDevice(drm_devices_[primary_graphics_card_path_],
+ handle->PassFD())) {
+ LOG(ERROR) << "Failed to add primary graphics device.";
+ }
}
void DrmDisplayHostManager::OnGpuThreadReady() {
@@ -343,8 +345,8 @@ void DrmDisplayHostManager::OnGpuThreadReady() {
if (!get_displays_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
- weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ base::BindOnce(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
get_displays_callback_.Reset();
}
@@ -384,8 +386,8 @@ void DrmDisplayHostManager::GpuHasUpdatedNativeDisplays(
if (!get_displays_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
- weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ base::BindOnce(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
get_displays_callback_.Reset();
}
}
@@ -435,7 +437,7 @@ void DrmDisplayHostManager::GpuTookDisplayControl(bool status) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(take_display_control_callback_, status));
+ FROM_HERE, base::BindOnce(take_display_control_callback_, status));
take_display_control_callback_.Reset();
display_control_change_pending_ = false;
}
@@ -455,7 +457,7 @@ void DrmDisplayHostManager::GpuRelinquishedDisplayControl(bool status) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
+ FROM_HERE, base::BindOnce(relinquish_display_control_callback_, status));
relinquish_display_control_callback_.Reset();
display_control_change_pending_ = false;
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
index 6c7f4f4b510..09632b10933 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -74,8 +74,8 @@ void CursorIPC::Move(gfx::AcceleratedWidget window, const gfx::Point& point) {
void CursorIPC::InitializeOnEvdevIfNecessary() {}
void CursorIPC::Send(IPC::Message* message) {
- if (IsConnected() &&
- send_runner_->PostTask(FROM_HERE, base::Bind(send_callback_, message)))
+ if (IsConnected() && send_runner_->PostTask(
+ FROM_HERE, base::BindOnce(send_callback_, message)))
return;
// Drop disconnected updates. DrmWindowHost will call
@@ -115,7 +115,8 @@ void DrmGpuPlatformSupportHost::RemoveGpuThreadObserver(
}
bool DrmGpuPlatformSupportHost::IsConnected() {
- return host_id_ >= 0 && channel_established_;
+ base::AutoLock auto_lock(host_id_lock_);
+ return host_id_ >= 0;
}
void DrmGpuPlatformSupportHost::OnGpuServiceLaunched(
@@ -139,27 +140,23 @@ void DrmGpuPlatformSupportHost::OnGpuProcessLaunched(
DCHECK(!ui_runner_->BelongsToCurrentThread());
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnGpuProcessLaunched",
"host_id", host_id);
- host_id_ = host_id;
- send_runner_ = std::move(send_runner);
- send_callback_ = send_callback;
-
- for (GpuThreadObserver& observer : gpu_thread_observers_)
- observer.OnGpuProcessLaunched();
ui_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DrmGpuPlatformSupportHost::OnChannelEstablished,
- weak_ptr_));
+ weak_ptr_, host_id, std::move(send_runner),
+ std::move(send_callback)));
}
void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) {
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelDestroyed",
"host_id", host_id);
-
if (host_id_ == host_id) {
+ {
+ base::AutoLock auto_lock(host_id_lock_);
+ host_id_ = -1;
+ }
cursor_->ResetDrmCursorProxy();
- host_id_ = -1;
- channel_established_ = false;
send_runner_ = nullptr;
send_callback_.Reset();
for (GpuThreadObserver& observer : gpu_thread_observers_)
@@ -182,8 +179,8 @@ void DrmGpuPlatformSupportHost::OnMessageReceived(const IPC::Message& message) {
}
bool DrmGpuPlatformSupportHost::Send(IPC::Message* message) {
- if (IsConnected() &&
- send_runner_->PostTask(FROM_HERE, base::Bind(send_callback_, message)))
+ if (IsConnected() && send_runner_->PostTask(
+ FROM_HERE, base::BindOnce(send_callback_, message)))
return true;
delete message;
@@ -200,9 +197,22 @@ void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmDisplayHostManager() {
display_manager_ = nullptr;
}
-void DrmGpuPlatformSupportHost::OnChannelEstablished() {
+void DrmGpuPlatformSupportHost::OnChannelEstablished(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::Callback<void(IPC::Message*)>& send_callback) {
+ DCHECK(ui_runner_->BelongsToCurrentThread());
TRACE_EVENT0("drm", "DrmGpuPlatformSupportHost::OnChannelEstablished");
- channel_established_ = true;
+
+ send_runner_ = std::move(send_runner);
+ send_callback_ = send_callback;
+ {
+ base::AutoLock auto_lock(host_id_lock_);
+ host_id_ = host_id;
+ }
+
+ for (GpuThreadObserver& observer : gpu_thread_observers_)
+ observer.OnGpuProcessLaunched();
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuThreadReady();
@@ -278,22 +288,8 @@ bool DrmGpuPlatformSupportHost::GpuRelinquishDisplayControl() {
bool DrmGpuPlatformSupportHost::GpuAddGraphicsDevice(const base::FilePath& path,
base::ScopedFD fd) {
- IPC::Message* message = new OzoneGpuMsg_AddGraphicsDevice(
- path, base::FileDescriptor(std::move(fd)));
-
- // This function may be called from two places:
- // - DrmDisplayHostManager::OnGpuProcessLaunched() invoked synchronously
- // by GpuProcessHost::Init() on IO thread, which is the same thread as
- // |send_runner_|. In this case we can synchronously send the IPC;
- // - DrmDisplayHostManager::OnAddGraphicsDevice() on UI thread. In this
- // case we need to post the send task to IO thread.
- if (send_runner_ && send_runner_->BelongsToCurrentThread()) {
- DCHECK(!send_callback_.is_null());
- send_callback_.Run(message);
- return true;
- }
-
- return Send(message);
+ return Send(new OzoneGpuMsg_AddGraphicsDevice(
+ path, base::FileDescriptor(std::move(fd))));
}
bool DrmGpuPlatformSupportHost::GpuRemoveGraphicsDevice(
diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
index ebcb9d5ea0d..4f0f918fdff 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
+++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/observer_list.h"
#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
@@ -99,7 +100,10 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost,
const gfx::Rect& bounds) override;
private:
- void OnChannelEstablished();
+ void OnChannelEstablished(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::Callback<void(IPC::Message*)>& send_callback);
bool OnMessageReceivedForDrmDisplayHostManager(const IPC::Message& message);
void OnUpdateNativeDisplays(
const std::vector<DisplaySnapshot_Params>& displays);
@@ -117,7 +121,7 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost,
const std::vector<OverlayCheckReturn_Params>& returns);
int host_id_ = -1;
- bool channel_established_ = false;
+ base::Lock host_id_lock_;
scoped_refptr<base::SingleThreadTaskRunner> ui_runner_;
scoped_refptr<base::SingleThreadTaskRunner> send_runner_;
diff --git a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.cc
index dc0f75a1f9e..4e8aae39f35 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
@@ -61,11 +60,6 @@ void DrmOverlayManager::CheckOverlaySupport(
continue;
}
- // Compositor doesn't have information about the total size of primary
- // candidate. We get this information from display rect.
- if (candidate.plane_z_order == 0)
- candidate.buffer_size = gfx::ToNearestRect(candidate.display_rect).size();
-
result_candidates.push_back(OverlaySurfaceCandidate(candidate));
// Start out hoping that we can have an overlay.
result_candidates.back().overlay_handled = true;
diff --git a/chromium/ui/ozone/platform/drm/host/drm_window_host.cc b/chromium/ui/ozone/platform/drm/host/drm_window_host.cc
index 3df6467ad0c..c3470c283c2 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_window_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -97,6 +97,10 @@ void DrmWindowHost::ReleaseCapture() {
window_manager_->UngrabEvents(widget_);
}
+bool DrmWindowHost::HasCapture() const {
+ return widget_ == window_manager_->event_grabber();
+}
+
void DrmWindowHost::ToggleFullscreen() {
}
@@ -129,9 +133,8 @@ PlatformImeController* DrmWindowHost::GetPlatformImeController() {
return nullptr;
}
-bool DrmWindowHost::CanDispatchEvent(const PlatformEvent& ne) {
- DCHECK(ne);
- Event* event = static_cast<Event*>(ne);
+bool DrmWindowHost::CanDispatchEvent(const PlatformEvent& event) {
+ DCHECK(event);
// If there is a grab, capture events here.
gfx::AcceleratedWidget grabber = window_manager_->event_grabber();
@@ -170,10 +173,9 @@ bool DrmWindowHost::CanDispatchEvent(const PlatformEvent& ne) {
return true;
}
-uint32_t DrmWindowHost::DispatchEvent(const PlatformEvent& native_event) {
- DCHECK(native_event);
+uint32_t DrmWindowHost::DispatchEvent(const PlatformEvent& event) {
+ DCHECK(event);
- Event* event = static_cast<Event*>(native_event);
if (event->IsLocatedEvent()) {
// Make the event location relative to this window's origin.
LocatedEvent* located_event = event->AsLocatedEvent();
@@ -183,8 +185,8 @@ uint32_t DrmWindowHost::DispatchEvent(const PlatformEvent& native_event) {
located_event->set_root_location_f(location);
}
DispatchEventFromNativeUiEvent(
- native_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
- base::Unretained(delegate_)));
+ event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
+ base::Unretained(delegate_)));
return POST_DISPATCH_STOP_PROPAGATION;
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_window_host.h b/chromium/ui/ozone/platform/drm/host/drm_window_host.h
index 01f0ccefce2..1b17b20c8c5 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_window_host.h
+++ b/chromium/ui/ozone/platform/drm/host/drm_window_host.h
@@ -67,6 +67,7 @@ class DrmWindowHost : public PlatformWindow,
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
diff --git a/chromium/ui/ozone/platform/drm/host/gpu_thread_observer.h b/chromium/ui/ozone/platform/drm/host/gpu_thread_observer.h
index ed6da90beac..24b5b19831e 100644
--- a/chromium/ui/ozone/platform/drm/host/gpu_thread_observer.h
+++ b/chromium/ui/ozone/platform/drm/host/gpu_thread_observer.h
@@ -7,20 +7,19 @@
namespace ui {
-// Observes the channel state.
+// Observes the channel state. All calls should happen on the same thread that
+// OzonePlatform::InitializeForUI() is called on. This can be the browser UI
+// thread or the WS thread for mus/mash.
class GpuThreadObserver {
public:
virtual ~GpuThreadObserver() {}
// Called when the GPU process is launched.
- // This is called from browser IO thread.
virtual void OnGpuProcessLaunched() = 0;
// Called when a GPU thread implementation has become available.
- // This is called from browser UI thread.
virtual void OnGpuThreadReady() = 0;
// Called when the GPU thread implementation has ceased to be
// available.
- // This is called from browser UI thread.
virtual void OnGpuThreadRetired() = 0;
};
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 963f77e8804..a6e1286c2a7 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -14,7 +14,6 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/ui/ozone/platform/headless/BUILD.gn b/chromium/ui/ozone/platform/headless/BUILD.gn
index 6de57300b13..0637f8e6f01 100644
--- a/chromium/ui/ozone/platform/headless/BUILD.gn
+++ b/chromium/ui/ozone/platform/headless/BUILD.gn
@@ -20,6 +20,8 @@ source_set("headless") {
"ozone_platform_headless.h",
]
+ defines = [ "OZONE_IMPLEMENTATION" ]
+
deps = [
"//base",
"//skia",
diff --git a/chromium/ui/ozone/platform/headless/gl_surface_osmesa_png.cc b/chromium/ui/ozone/platform/headless/gl_surface_osmesa_png.cc
index 8700136a9f7..2bbb7a86b7e 100644
--- a/chromium/ui/ozone/platform/headless/gl_surface_osmesa_png.cc
+++ b/chromium/ui/ozone/platform/headless/gl_surface_osmesa_png.cc
@@ -67,7 +67,7 @@ void GLSurfaceOSMesaPng::WriteBufferToPng() {
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
- base::Bind(&WritePngToFile, output_path_, base::Passed(&png_data)));
+ base::BindOnce(&WritePngToFile, output_path_, std::move(png_data)));
}
}
diff --git a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc
index 6e64f51c583..7bfe64670d3 100644
--- a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -8,7 +8,6 @@
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
@@ -28,6 +27,8 @@ namespace ui {
namespace {
+const base::FilePath::CharType kDevNull[] = FILE_PATH_LITERAL("/dev/null");
+
void WriteDataToFile(const base::FilePath& location, const SkBitmap& bitmap) {
DCHECK(!location.empty());
std::vector<unsigned char> png_data;
@@ -60,7 +61,7 @@ class FileSurface : public SurfaceOzoneCanvas {
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
- base::Bind(&WriteDataToFile, base_path_, bitmap));
+ base::BindOnce(&WriteDataToFile, base_path_, bitmap));
}
}
std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
@@ -90,7 +91,8 @@ class TestPixmap : public gfx::NativePixmap {
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
- const gfx::RectF& crop_rect) override {
+ const gfx::RectF& crop_rect,
+ bool enable_blend) override {
return true;
}
gfx::NativePixmapHandle ExportHandle() override {
@@ -137,7 +139,7 @@ HeadlessSurfaceFactory::~HeadlessSurfaceFactory() = default;
base::FilePath HeadlessSurfaceFactory::GetPathForWidget(
gfx::AcceleratedWidget widget) {
- if (base_path_.empty() || base_path_ == base::FilePath("/dev/null"))
+ if (base_path_.empty() || base_path_ == base::FilePath(kDevNull))
return base_path_;
// Disambiguate multiple window output files with the window id.
@@ -177,7 +179,7 @@ void HeadlessSurfaceFactory::CheckBasePath() const {
return;
if (!DirectoryExists(base_path_) && !base::CreateDirectory(base_path_) &&
- base_path_ != base::FilePath("/dev/null"))
+ base_path_ != base::FilePath(kDevNull))
PLOG(FATAL) << "Unable to create output directory";
if (!base::PathIsWritable(base_path_))
diff --git a/chromium/ui/ozone/platform/headless/headless_window.cc b/chromium/ui/ozone/platform/headless/headless_window.cc
index 3608ffa4255..5bf6e7c9653 100644
--- a/chromium/ui/ozone/platform/headless/headless_window.cc
+++ b/chromium/ui/ozone/platform/headless/headless_window.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "build/build_config.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/ozone/platform/headless/headless_window_manager.h"
#include "ui/platform_window/platform_window_delegate.h"
@@ -16,12 +17,20 @@ HeadlessWindow::HeadlessWindow(PlatformWindowDelegate* delegate,
HeadlessWindowManager* manager,
const gfx::Rect& bounds)
: delegate_(delegate), manager_(manager), bounds_(bounds) {
+#if defined(OS_WIN)
+ widget_ = reinterpret_cast<gfx::AcceleratedWidget>(manager_->AddWindow(this));
+#else
widget_ = manager_->AddWindow(this);
+#endif
delegate_->OnAcceleratedWidgetAvailable(widget_, 1.f);
}
HeadlessWindow::~HeadlessWindow() {
+#if defined(OS_WIN)
+ manager_->RemoveWindow(reinterpret_cast<uint64_t>(widget_), this);
+#else
manager_->RemoveWindow(widget_, this);
+#endif
}
gfx::Rect HeadlessWindow::GetBounds() {
@@ -47,6 +56,10 @@ void HeadlessWindow::SetCapture() {}
void HeadlessWindow::ReleaseCapture() {}
+bool HeadlessWindow::HasCapture() const {
+ return false;
+}
+
void HeadlessWindow::ToggleFullscreen() {}
void HeadlessWindow::Maximize() {}
diff --git a/chromium/ui/ozone/platform/headless/headless_window.h b/chromium/ui/ozone/platform/headless/headless_window.h
index 4e909cf6e4e..2051d143cb9 100644
--- a/chromium/ui/ozone/platform/headless/headless_window.h
+++ b/chromium/ui/ozone/platform/headless/headless_window.h
@@ -32,6 +32,7 @@ class HeadlessWindow : public PlatformWindow {
void PrepareForShutdown() override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
index 8c569f49131..e6935b79eaf 100644
--- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -7,7 +7,6 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/display/manager/fake_display_delegate.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -31,7 +30,7 @@ namespace {
// A headless implementation of PlatformEventSource that we can instantiate to
// make
// sure that the PlatformEventSource has an instance while in unit tests.
-class HeadlessPlatformEventSource : public ui::PlatformEventSource {
+class HeadlessPlatformEventSource : public PlatformEventSource {
public:
HeadlessPlatformEventSource() = default;
~HeadlessPlatformEventSource() override = default;
diff --git a/chromium/ui/ozone/platform/wayland/fake_server.cc b/chromium/ui/ozone/platform/wayland/fake_server.cc
index 7adfe81029e..84c6594cb95 100644
--- a/chromium/ui/ozone/platform/wayland/fake_server.cc
+++ b/chromium/ui/ozone/platform/wayland/fake_server.cc
@@ -23,6 +23,11 @@ const uint32_t kOutputVersion = 2;
const uint32_t kSeatVersion = 4;
const uint32_t kXdgShellVersion = 1;
+template <class T>
+T* GetUserDataAs(wl_resource* resource) {
+ return static_cast<T*>(wl_resource_get_user_data(resource));
+}
+
void DestroyResource(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
@@ -30,8 +35,7 @@ void DestroyResource(wl_client* client, wl_resource* resource) {
// wl_compositor
void CreateSurface(wl_client* client, wl_resource* resource, uint32_t id) {
- auto* compositor =
- static_cast<MockCompositor*>(wl_resource_get_user_data(resource));
+ auto* compositor = GetUserDataAs<MockCompositor>(resource);
wl_resource* surface_resource = wl_resource_create(
client, &wl_surface_interface, wl_resource_get_version(resource), id);
if (!surface_resource) {
@@ -53,8 +57,7 @@ void Attach(wl_client* client,
wl_resource* buffer_resource,
int32_t x,
int32_t y) {
- static_cast<MockSurface*>(wl_resource_get_user_data(resource))
- ->Attach(buffer_resource, x, y);
+ GetUserDataAs<MockSurface>(resource)->Attach(buffer_resource, x, y);
}
void Damage(wl_client* client,
@@ -63,12 +66,11 @@ void Damage(wl_client* client,
int32_t y,
int32_t width,
int32_t height) {
- static_cast<MockSurface*>(wl_resource_get_user_data(resource))
- ->Damage(x, y, width, height);
+ GetUserDataAs<MockSurface>(resource)->Damage(x, y, width, height);
}
void Commit(wl_client* client, wl_resource* resource) {
- static_cast<MockSurface*>(wl_resource_get_user_data(resource))->Commit();
+ GetUserDataAs<MockSurface>(resource)->Commit();
}
const struct wl_surface_interface surface_impl = {
@@ -89,14 +91,13 @@ const struct wl_surface_interface surface_impl = {
void UseUnstableVersion(wl_client* client,
wl_resource* resource,
int32_t version) {
- static_cast<MockXdgShell*>(wl_resource_get_user_data(resource))
- ->UseUnstableVersion(version);
+ GetUserDataAs<MockXdgShell>(resource)->UseUnstableVersion(version);
}
// xdg_shell and zxdg_shell_v6
void Pong(wl_client* client, wl_resource* resource, uint32_t serial) {
- static_cast<MockXdgShell*>(wl_resource_get_user_data(resource))->Pong(serial);
+ GetUserDataAs<MockXdgShell>(resource)->Pong(serial);
}
// xdg_shell
@@ -131,36 +132,36 @@ const struct zxdg_shell_v6_interface zxdg_shell_v6_impl = {
// wl_seat
void GetPointer(wl_client* client, wl_resource* resource, uint32_t id) {
- auto* seat = static_cast<MockSeat*>(wl_resource_get_user_data(resource));
wl_resource* pointer_resource = wl_resource_create(
client, &wl_pointer_interface, wl_resource_get_version(resource), id);
if (!pointer_resource) {
wl_client_post_no_memory(client);
return;
}
- seat->pointer.reset(new MockPointer(pointer_resource));
+ auto* seat = GetUserDataAs<MockSeat>(resource);
+ seat->set_pointer(std::make_unique<MockPointer>(pointer_resource));
}
void GetKeyboard(wl_client* client, wl_resource* resource, uint32_t id) {
- auto* seat = static_cast<MockSeat*>(wl_resource_get_user_data(resource));
wl_resource* keyboard_resource = wl_resource_create(
client, &wl_keyboard_interface, wl_resource_get_version(resource), id);
if (!keyboard_resource) {
wl_client_post_no_memory(client);
return;
}
- seat->keyboard.reset(new MockKeyboard(keyboard_resource));
+ auto* seat = GetUserDataAs<MockSeat>(resource);
+ seat->set_keyboard(std::make_unique<MockKeyboard>(keyboard_resource));
}
void GetTouch(wl_client* client, wl_resource* resource, uint32_t id) {
- auto* seat = static_cast<MockSeat*>(wl_resource_get_user_data(resource));
wl_resource* touch_resource = wl_resource_create(
client, &wl_touch_interface, wl_resource_get_version(resource), id);
if (!touch_resource) {
wl_client_post_no_memory(client);
return;
}
- seat->touch.reset(new MockTouch(touch_resource));
+ auto* seat = GetUserDataAs<MockSeat>(resource);
+ seat->set_touch(std::make_unique<MockTouch>(touch_resource));
}
const struct wl_seat_interface seat_impl = {
@@ -192,18 +193,15 @@ const struct wl_touch_interface touch_impl = {
// xdg_surface, zxdg_surface_v6 and zxdg_toplevel shared methods.
void SetTitle(wl_client* client, wl_resource* resource, const char* title) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetTitle(title);
+ GetUserDataAs<MockXdgSurface>(resource)->SetTitle(title);
}
void SetAppId(wl_client* client, wl_resource* resource, const char* app_id) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetAppId(app_id);
+ GetUserDataAs<MockXdgSurface>(resource)->SetAppId(app_id);
}
void AckConfigure(wl_client* client, wl_resource* resource, uint32_t serial) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->AckConfigure(serial);
+ GetUserDataAs<MockXdgSurface>(resource)->AckConfigure(serial);
}
void SetWindowGeometry(wl_client* client,
@@ -212,35 +210,30 @@ void SetWindowGeometry(wl_client* client,
int32_t y,
int32_t width,
int32_t height) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetWindowGeometry(x, y, width, height);
+ GetUserDataAs<MockXdgSurface>(resource)->SetWindowGeometry(x, y, width,
+ height);
}
void SetMaximized(wl_client* client, wl_resource* resource) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetMaximized();
+ GetUserDataAs<MockXdgSurface>(resource)->SetMaximized();
}
void UnsetMaximized(wl_client* client, wl_resource* resource) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->UnsetMaximized();
+ GetUserDataAs<MockXdgSurface>(resource)->UnsetMaximized();
}
void SetFullscreen(wl_client* client,
wl_resource* resource,
wl_resource* output) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetFullscreen();
+ GetUserDataAs<MockXdgSurface>(resource)->SetFullscreen();
}
void UnsetFullscreen(wl_client* client, wl_resource* resource) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->UnsetFullscreen();
+ GetUserDataAs<MockXdgSurface>(resource)->UnsetFullscreen();
}
void SetMinimized(wl_client* client, wl_resource* resource) {
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource))
- ->SetMinimized();
+ GetUserDataAs<MockXdgSurface>(resource)->SetMinimized();
}
const struct xdg_surface_interface xdg_surface_impl = {
@@ -263,9 +256,8 @@ const struct xdg_surface_interface xdg_surface_impl = {
// zxdg_surface specific interface
void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) {
- auto* surface =
- static_cast<MockXdgSurface*>(wl_resource_get_user_data(resource));
- if (surface->xdg_toplevel) {
+ auto* surface = GetUserDataAs<MockXdgSurface>(resource);
+ if (surface->xdg_toplevel()) {
wl_resource_post_error(resource, ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
"surface has already been constructed");
return;
@@ -276,7 +268,8 @@ void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) {
wl_client_post_no_memory(client);
return;
}
- surface->xdg_toplevel.reset(new MockXdgTopLevel(xdg_toplevel_resource));
+ surface->set_xdg_toplevel(
+ std::make_unique<MockXdgTopLevel>(xdg_toplevel_resource));
}
const struct zxdg_surface_v6_interface zxdg_surface_v6_impl = {
@@ -310,9 +303,8 @@ void GetXdgSurfaceImpl(wl_client* client,
wl_resource* surface_resource,
const struct wl_interface* interface,
const void* implementation) {
- auto* surface =
- static_cast<MockSurface*>(wl_resource_get_user_data(surface_resource));
- if (surface->xdg_surface) {
+ auto* surface = GetUserDataAs<MockSurface>(surface_resource);
+ if (surface->xdg_surface()) {
uint32_t xdg_error = implementation == &xdg_surface_impl
? XDG_SHELL_ERROR_ROLE
: ZXDG_SHELL_V6_ERROR_ROLE;
@@ -326,8 +318,8 @@ void GetXdgSurfaceImpl(wl_client* client,
wl_client_post_no_memory(client);
return;
}
- surface->xdg_surface.reset(
- new MockXdgSurface(xdg_surface_resource, implementation));
+ surface->set_xdg_surface(
+ std::make_unique<MockXdgSurface>(xdg_surface_resource, implementation));
}
// xdg_shell
@@ -361,60 +353,62 @@ ServerObject::~ServerObject() {
// static
void ServerObject::OnResourceDestroyed(wl_resource* resource) {
- auto* obj = static_cast<ServerObject*>(wl_resource_get_user_data(resource));
+ auto* obj = GetUserDataAs<ServerObject>(resource);
obj->resource_ = nullptr;
}
+template <class T>
+void SetImplementation(wl_resource* resource,
+ const void* implementation,
+ T* user_data) {
+ wl_resource_set_implementation(resource, implementation, user_data,
+ &ServerObject::OnResourceDestroyed);
+}
+
MockXdgSurface::MockXdgSurface(wl_resource* resource,
const void* implementation)
: ServerObject(resource) {
- wl_resource_set_implementation(resource, implementation, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, implementation, this);
}
MockXdgSurface::~MockXdgSurface() {}
MockXdgTopLevel::MockXdgTopLevel(wl_resource* resource)
: MockXdgSurface(resource, &zxdg_surface_v6_impl) {
- wl_resource_set_implementation(resource, &zxdg_toplevel_v6_impl, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, &zxdg_toplevel_v6_impl, this);
}
MockXdgTopLevel::~MockXdgTopLevel() {}
MockSurface::MockSurface(wl_resource* resource) : ServerObject(resource) {
- wl_resource_set_implementation(resource, &surface_impl, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, &surface_impl, this);
}
MockSurface::~MockSurface() {
- if (xdg_surface && xdg_surface->resource())
- wl_resource_destroy(xdg_surface->resource());
+ if (xdg_surface_ && xdg_surface_->resource())
+ wl_resource_destroy(xdg_surface_->resource());
}
MockSurface* MockSurface::FromResource(wl_resource* resource) {
if (!wl_resource_instance_of(resource, &wl_surface_interface, &surface_impl))
return nullptr;
- return static_cast<MockSurface*>(wl_resource_get_user_data(resource));
+ return GetUserDataAs<MockSurface>(resource);
}
MockPointer::MockPointer(wl_resource* resource) : ServerObject(resource) {
- wl_resource_set_implementation(resource, &pointer_impl, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, &pointer_impl, this);
}
MockPointer::~MockPointer() {}
MockKeyboard::MockKeyboard(wl_resource* resource) : ServerObject(resource) {
- wl_resource_set_implementation(resource, &keyboard_impl, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, &keyboard_impl, this);
}
MockKeyboard::~MockKeyboard() {}
MockTouch::MockTouch(wl_resource* resource) : ServerObject(resource) {
- wl_resource_set_implementation(resource, &touch_impl, this,
- &ServerObject::OnResourceDestroyed);
+ SetImplementation(resource, &touch_impl, this);
}
MockTouch::~MockTouch() {}
@@ -451,14 +445,13 @@ void Global::Bind(wl_client* client,
}
if (!global->resource_)
global->resource_ = resource;
- wl_resource_set_implementation(resource, global->implementation_, global,
- &Global::OnResourceDestroyed);
+ SetImplementation(resource, global->implementation_, global);
global->OnBind();
}
// static
void Global::OnResourceDestroyed(wl_resource* resource) {
- auto* global = static_cast<Global*>(wl_resource_get_user_data(resource));
+ auto* global = GetUserDataAs<Global>(resource);
if (global->resource_ == resource)
global->resource_ = nullptr;
}
@@ -552,8 +545,8 @@ bool FakeServer::Start(uint32_t shell_version) {
(void)server_fd.release();
base::Thread::Options options;
- options.message_pump_factory =
- base::Bind(&FakeServer::CreateMessagePump, base::Unretained(this));
+ options.message_pump_factory = base::BindRepeating(
+ &FakeServer::CreateMessagePump, base::Unretained(this));
if (!base::Thread::StartWithOptions(options))
return false;
@@ -564,7 +557,7 @@ bool FakeServer::Start(uint32_t shell_version) {
void FakeServer::Pause() {
task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeServer::DoPause, base::Unretained(this)));
+ FROM_HERE, base::BindOnce(&FakeServer::DoPause, base::Unretained(this)));
pause_event_.Wait();
}
diff --git a/chromium/ui/ozone/platform/wayland/fake_server.h b/chromium/ui/ozone/platform/wayland/fake_server.h
index 816f5815e6f..24e3863053d 100644
--- a/chromium/ui/ozone/platform/wayland/fake_server.h
+++ b/chromium/ui/ozone/platform/wayland/fake_server.h
@@ -25,7 +25,7 @@ namespace wl {
// Base class for managing the life cycle of server objects.
class ServerObject {
public:
- ServerObject(wl_resource* resource);
+ explicit ServerObject(wl_resource* resource);
virtual ~ServerObject();
wl_resource* resource() { return resource_; }
@@ -54,24 +54,29 @@ class MockXdgSurface : public ServerObject {
MOCK_METHOD1(SetAppId, void(const char* app_id));
MOCK_METHOD1(AckConfigure, void(uint32_t serial));
MOCK_METHOD4(SetWindowGeometry,
- void(int32_t x, int32_t y, int32_t widht, int32_t height));
+ void(int32_t x, int32_t y, int32_t width, int32_t height));
MOCK_METHOD0(SetMaximized, void());
MOCK_METHOD0(UnsetMaximized, void());
MOCK_METHOD0(SetFullscreen, void());
MOCK_METHOD0(UnsetFullscreen, void());
MOCK_METHOD0(SetMinimized, void());
- // Used when xdg v6 is used.
- std::unique_ptr<MockXdgTopLevel> xdg_toplevel;
+ void set_xdg_toplevel(std::unique_ptr<MockXdgTopLevel> xdg_toplevel) {
+ xdg_toplevel_ = std::move(xdg_toplevel);
+ }
+ MockXdgTopLevel* xdg_toplevel() { return xdg_toplevel_.get(); }
private:
+ // Used when xdg v6 is used.
+ std::unique_ptr<MockXdgTopLevel> xdg_toplevel_;
+
DISALLOW_COPY_AND_ASSIGN(MockXdgSurface);
};
// Manage zxdg_toplevel for providing desktop UI.
class MockXdgTopLevel : public MockXdgSurface {
public:
- MockXdgTopLevel(wl_resource* resource);
+ explicit MockXdgTopLevel(wl_resource* resource);
~MockXdgTopLevel() override;
// TODO(msisov): mock other zxdg_toplevel specific methods once implementation
@@ -85,7 +90,7 @@ class MockXdgTopLevel : public MockXdgSurface {
// Manage client surface
class MockSurface : public ServerObject {
public:
- MockSurface(wl_resource* resource);
+ explicit MockSurface(wl_resource* resource);
~MockSurface() override;
static MockSurface* FromResource(wl_resource* resource);
@@ -95,15 +100,20 @@ class MockSurface : public ServerObject {
void(int32_t x, int32_t y, int32_t width, int32_t height));
MOCK_METHOD0(Commit, void());
- std::unique_ptr<MockXdgSurface> xdg_surface;
+ void set_xdg_surface(std::unique_ptr<MockXdgSurface> xdg_surface) {
+ xdg_surface_ = std::move(xdg_surface);
+ }
+ MockXdgSurface* xdg_surface() { return xdg_surface_.get(); }
private:
+ std::unique_ptr<MockXdgSurface> xdg_surface_;
+
DISALLOW_COPY_AND_ASSIGN(MockSurface);
};
class MockPointer : public ServerObject {
public:
- MockPointer(wl_resource* resource);
+ explicit MockPointer(wl_resource* resource);
~MockPointer() override;
private:
@@ -112,7 +122,7 @@ class MockPointer : public ServerObject {
class MockKeyboard : public ServerObject {
public:
- MockKeyboard(wl_resource* resource);
+ explicit MockKeyboard(wl_resource* resource);
~MockKeyboard() override;
private:
@@ -207,11 +217,26 @@ class MockSeat : public Global {
MockSeat();
~MockSeat() override;
- std::unique_ptr<MockPointer> pointer;
- std::unique_ptr<MockKeyboard> keyboard;
- std::unique_ptr<MockTouch> touch;
+ void set_pointer(std::unique_ptr<MockPointer> pointer) {
+ pointer_ = std::move(pointer);
+ }
+ MockPointer* pointer() { return pointer_.get(); }
+
+ void set_keyboard(std::unique_ptr<MockKeyboard> keyboard) {
+ keyboard_ = std::move(keyboard);
+ }
+ MockKeyboard* keyboard() { return keyboard_.get(); }
+
+ void set_touch(std::unique_ptr<MockTouch> touch) {
+ touch_ = std::move(touch);
+ }
+ MockTouch* touch() { return touch_.get(); }
private:
+ std::unique_ptr<MockPointer> pointer_;
+ std::unique_ptr<MockKeyboard> keyboard_;
+ std::unique_ptr<MockTouch> touch_;
+
DISALLOW_COPY_AND_ASSIGN(MockSeat);
};
@@ -244,7 +269,7 @@ struct DisplayDeleter {
void operator()(wl_display* display);
};
-class FakeServer : public base::Thread, base::MessagePumpLibevent::Watcher {
+class FakeServer : public base::Thread, base::MessagePumpLibevent::FdWatcher {
public:
FakeServer();
~FakeServer() override;
@@ -278,7 +303,7 @@ class FakeServer : public base::Thread, base::MessagePumpLibevent::Watcher {
std::unique_ptr<base::MessagePump> CreateMessagePump();
- // base::MessagePumpLibevent::Watcher
+ // base::MessagePumpLibevent::FdWatcher
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
@@ -296,7 +321,7 @@ class FakeServer : public base::Thread, base::MessagePumpLibevent::Watcher {
MockXdgShell xdg_shell_;
MockXdgShellV6 zxdg_shell_v6_;
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
DISALLOW_COPY_AND_ASSIGN(FakeServer);
};
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 843d7c99fdf..f0774bf1211 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -4,7 +4,6 @@
#include "ui/ozone/platform/wayland/ozone_platform_wayland.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ui_features.h"
#include "ui/display/manager/fake_display_delegate.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
index 89cf855b386..a90445be880 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
@@ -92,7 +92,8 @@ void WaylandConnection::ScheduleFlush() {
return;
DCHECK(base::MessageLoopForUI::IsCurrent());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&WaylandConnection::Flush, base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&WaylandConnection::Flush, base::Unretained(this)));
scheduled_flush_ = true;
}
@@ -253,8 +254,8 @@ void WaylandConnection::Capabilities(void* data,
return;
}
connection->pointer_ = std::make_unique<WaylandPointer>(
- pointer, base::Bind(&WaylandConnection::DispatchUiEvent,
- base::Unretained(connection)));
+ pointer, base::BindRepeating(&WaylandConnection::DispatchUiEvent,
+ base::Unretained(connection)));
connection->pointer_->set_connection(connection);
}
} else if (connection->pointer_) {
@@ -268,8 +269,8 @@ void WaylandConnection::Capabilities(void* data,
return;
}
connection->keyboard_ = std::make_unique<WaylandKeyboard>(
- keyboard, base::Bind(&WaylandConnection::DispatchUiEvent,
- base::Unretained(connection)));
+ keyboard, base::BindRepeating(&WaylandConnection::DispatchUiEvent,
+ base::Unretained(connection)));
connection->keyboard_->set_connection(connection);
}
} else if (connection->keyboard_) {
@@ -283,8 +284,8 @@ void WaylandConnection::Capabilities(void* data,
return;
}
connection->touch_ = std::make_unique<WaylandTouch>(
- touch, base::Bind(&WaylandConnection::DispatchUiEvent,
- base::Unretained(connection)));
+ touch, base::BindRepeating(&WaylandConnection::DispatchUiEvent,
+ base::Unretained(connection)));
connection->touch_->set_connection(connection);
}
} else if (connection->touch_) {
diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.h b/chromium/ui/ozone/platform/wayland/wayland_connection.h
index e745efd5b6b..747a11a465a 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_connection.h
@@ -21,7 +21,7 @@ namespace ui {
class WaylandWindow;
class WaylandConnection : public PlatformEventSource,
- public base::MessagePumpLibevent::Watcher {
+ public base::MessagePumpLibevent::FdWatcher {
public:
WaylandConnection();
~WaylandConnection() override;
@@ -53,6 +53,9 @@ class WaylandConnection : public PlatformEventSource,
int GetKeyboardModifiers();
+ // Returns the current pointer, which may be null.
+ WaylandPointer* pointer() { return pointer_.get(); }
+
private:
void Flush();
void DispatchUiEvent(Event* event);
@@ -60,7 +63,7 @@ class WaylandConnection : public PlatformEventSource,
// PlatformEventSource
void OnDispatcherListChanged() override;
- // base::MessagePumpLibevent::Watcher
+ // base::MessagePumpLibevent::FdWatcher
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
@@ -98,7 +101,7 @@ class WaylandConnection : public PlatformEventSource,
bool scheduled_flush_ = false;
bool watching_ = false;
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ base::MessagePumpLibevent::FdWatchController controller_;
uint32_t serial_ = 0;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
index 7ce077a7e97..492152b68b2 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
@@ -31,13 +31,13 @@ class WaylandKeyboardTest : public WaylandTest {
void SetUp() override {
WaylandTest::SetUp();
- wl_seat_send_capabilities(server.seat()->resource(),
+ wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_KEYBOARD);
Sync();
- keyboard = server.seat()->keyboard.get();
- ASSERT_TRUE(keyboard);
+ keyboard_ = server_.seat()->keyboard();
+ ASSERT_TRUE(keyboard_);
#if BUILDFLAG(USE_XKBCOMMON)
// Set up XKB bits and set the keymap to the client.
@@ -54,14 +54,14 @@ class WaylandKeyboardTest : public WaylandTest {
bool rv = shared_keymap.CreateAndMapAnonymous(keymap_size);
DCHECK(rv);
memcpy(shared_keymap.memory(), keymap_string.get(), keymap_size);
- wl_keyboard_send_keymap(keyboard->resource(),
+ wl_keyboard_send_keymap(keyboard_->resource(),
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
shared_keymap.handle().GetHandle(), keymap_size);
#endif
}
protected:
- wl::MockKeyboard* keyboard;
+ wl::MockKeyboard* keyboard_;
private:
#if BUILDFLAG(USE_XKBCOMMON)
@@ -81,14 +81,15 @@ ACTION_P(CloneEvent, ptr) {
TEST_P(WaylandKeyboardTest, Keypress) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
ASSERT_TRUE(event);
@@ -98,27 +99,28 @@ TEST_P(WaylandKeyboardTest, Keypress) {
EXPECT_EQ(ui::VKEY_A, key_event->key_code());
EXPECT_EQ(ET_KEY_PRESSED, key_event->type());
- wl_keyboard_send_leave(keyboard->resource(), 3, surface->resource());
+ wl_keyboard_send_leave(keyboard_->resource(), 3, surface_->resource());
Sync();
- wl_keyboard_send_key(keyboard->resource(), 3, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 3, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
- EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
}
TEST_P(WaylandKeyboardTest, AltModifierKeypress) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Alt
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 56 /* left Alt */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 56 /* left Alt */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
ASSERT_TRUE(event);
@@ -134,15 +136,16 @@ TEST_P(WaylandKeyboardTest, AltModifierKeypress) {
TEST_P(WaylandKeyboardTest, ControlModifierKeypress) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Control
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 29 /* left Control */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 29 /* left Control */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
ASSERT_TRUE(event);
@@ -158,15 +161,16 @@ TEST_P(WaylandKeyboardTest, ControlModifierKeypress) {
TEST_P(WaylandKeyboardTest, ShiftModifierKeypress) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Shift
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 42 /* left Shift */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 42 /* left Shift */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
ASSERT_TRUE(event);
@@ -183,41 +187,42 @@ TEST_P(WaylandKeyboardTest, ControlShiftModifiers) {
struct wl_array empty;
wl_array_init(&empty);
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Pressing control.
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 29 /* Control */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 29 /* Control */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
- wl_keyboard_send_modifiers(keyboard->resource(), 3, 4 /* mods_depressed*/,
+ wl_keyboard_send_modifiers(keyboard_->resource(), 3, 4 /* mods_depressed*/,
0 /* mods_latched */, 0 /* mods_locked */,
0 /* group */);
Sync();
// Pressing shift (with control key still held down).
- wl_keyboard_send_key(keyboard->resource(), 4, 0, 42 /* Shift */,
+ wl_keyboard_send_key(keyboard_->resource(), 4, 0, 42 /* Shift */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event2;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
Sync();
- wl_keyboard_send_modifiers(keyboard->resource(), 5, 5 /* mods_depressed*/,
+ wl_keyboard_send_modifiers(keyboard_->resource(), 5, 5 /* mods_depressed*/,
0 /* mods_latched */, 0 /* mods_locked */,
0 /* group */);
Sync();
// Sending a reguard keypress, eg 'a'.
- wl_keyboard_send_key(keyboard->resource(), 6, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 6, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event3;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event3));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event3));
Sync();
ASSERT_TRUE(event3);
@@ -234,15 +239,16 @@ TEST_P(WaylandKeyboardTest, CapsLockKeypress) {
struct wl_array empty;
wl_array_init(&empty);
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Capslock
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 58 /* Capslock */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 58 /* Capslock */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
ASSERT_TRUE(event);
@@ -256,11 +262,11 @@ TEST_P(WaylandKeyboardTest, CapsLockKeypress) {
Sync();
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 58 /* Capslock */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 58 /* Capslock */,
WL_KEYBOARD_KEY_STATE_RELEASED);
std::unique_ptr<Event> event2;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
Sync();
ASSERT_TRUE(event2);
@@ -278,41 +284,42 @@ TEST_P(WaylandKeyboardTest, CapsLockModifier) {
struct wl_array empty;
wl_array_init(&empty);
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Pressing capslock (led ON).
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 58 /* Capslock */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 58 /* Capslock */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
- wl_keyboard_send_modifiers(keyboard->resource(), 3, 2 /* mods_depressed*/,
+ wl_keyboard_send_modifiers(keyboard_->resource(), 3, 2 /* mods_depressed*/,
0 /* mods_latched */, 2 /* mods_locked */,
0 /* group */);
Sync();
// Releasing capslock (led ON).
- wl_keyboard_send_key(keyboard->resource(), 4, 0, 58 /* Capslock */,
+ wl_keyboard_send_key(keyboard_->resource(), 4, 0, 58 /* Capslock */,
WL_KEYBOARD_KEY_STATE_RELEASED);
std::unique_ptr<Event> event2;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
Sync();
- wl_keyboard_send_modifiers(keyboard->resource(), 5, 0 /* mods_depressed*/,
+ wl_keyboard_send_modifiers(keyboard_->resource(), 5, 0 /* mods_depressed*/,
0 /* mods_latched */, 2 /* mods_locked */,
0 /* group */);
Sync();
// Sending a reguard keypress, eg 'a'.
- wl_keyboard_send_key(keyboard->resource(), 6, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 6, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event3;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event3));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event3));
Sync();
ASSERT_TRUE(event3);
@@ -330,20 +337,21 @@ TEST_P(WaylandKeyboardTest, EventAutoRepeat) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Auto repeat info in ms.
uint32_t rate = 75;
uint32_t delay = 25;
- wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+ wl_keyboard_send_repeat_info(keyboard_->resource(), rate, delay);
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
@@ -361,9 +369,9 @@ TEST_P(WaylandKeyboardTest, EventAutoRepeat) {
Sync();
std::unique_ptr<Event> event2;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event2));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event2));
- wl_keyboard_send_key(keyboard->resource(), 3, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 3, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_RELEASED);
Sync();
}
@@ -372,20 +380,21 @@ TEST_P(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Auto repeat info in ms.
uint32_t rate = 75;
uint32_t delay = 25;
- wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+ wl_keyboard_send_repeat_info(keyboard_->resource(), rate, delay);
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
@@ -400,13 +409,13 @@ TEST_P(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) {
base::TimeDelta::FromMilliseconds(rate * 2));
}
- wl_keyboard_send_leave(keyboard->resource(), 3, surface->resource());
+ wl_keyboard_send_leave(keyboard_->resource(), 3, surface_->resource());
Sync();
- EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
- wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 4, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_RELEASED);
Sync();
}
@@ -415,20 +424,21 @@ TEST_P(WaylandKeyboardTest, NoEventAutoRepeatBeforeTimeout) {
struct wl_array empty;
wl_array_init(&empty);
- wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+ wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(),
+ &empty);
wl_array_release(&empty);
// Auto repeat info in ms.
uint32_t rate = 500;
uint32_t delay = 50;
- wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+ wl_keyboard_send_repeat_info(keyboard_->resource(), rate, delay);
- wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 2, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_PRESSED);
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
@@ -444,11 +454,11 @@ TEST_P(WaylandKeyboardTest, NoEventAutoRepeatBeforeTimeout) {
base::TimeDelta::FromMilliseconds(rate / 5));
}
- wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */,
+ wl_keyboard_send_key(keyboard_->resource(), 4, 0, 30 /* a */,
WL_KEYBOARD_KEY_STATE_RELEASED);
std::unique_ptr<Event> event2;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
Sync();
ASSERT_TRUE(event2);
diff --git a/chromium/ui/ozone/platform/wayland/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
index 9d6f4ae78e3..8d74daf9b73 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_pointer.cc
@@ -23,6 +23,12 @@ bool VerifyFlagsAfterMasking(int flags, int original_flags, int modifiers) {
return flags == original_flags;
}
+bool HasAnyButtonFlag(int flags) {
+ return (flags & (EF_LEFT_MOUSE_BUTTON | EF_MIDDLE_MOUSE_BUTTON |
+ EF_RIGHT_MOUSE_BUTTON | EF_BACK_MOUSE_BUTTON |
+ EF_FORWARD_MOUSE_BUTTON)) != 0;
+}
+
} // namespace
WaylandPointer::WaylandPointer(wl_pointer* pointer,
@@ -38,7 +44,12 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
cursor_.reset(new WaylandCursor);
}
-WaylandPointer::~WaylandPointer() {}
+WaylandPointer::~WaylandPointer() {
+ if (window_with_pointer_focus_) {
+ window_with_pointer_focus_->set_pointer_focus(false);
+ window_with_pointer_focus_->set_has_implicit_grab(false);
+ }
+}
// static
void WaylandPointer::Enter(void* data,
@@ -50,8 +61,11 @@ void WaylandPointer::Enter(void* data,
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
pointer->location_.SetPoint(wl_fixed_to_double(surface_x),
wl_fixed_to_double(surface_y));
- if (surface)
- WaylandWindow::FromSurface(surface)->set_pointer_focus(true);
+ if (surface) {
+ WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ window->set_pointer_focus(true);
+ pointer->window_with_pointer_focus_ = window;
+ }
}
// static
@@ -63,8 +77,11 @@ void WaylandPointer::Leave(void* data,
MouseEvent event(ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
EventTimeForNow(), pointer->flags_, 0);
pointer->callback_.Run(&event);
- if (surface)
- WaylandWindow::FromSurface(surface)->set_pointer_focus(false);
+ if (surface) {
+ WaylandWindow* window = WaylandWindow::FromSurface(surface);
+ window->set_pointer_focus(false);
+ pointer->window_with_pointer_focus_ = nullptr;
+ }
}
// static
@@ -92,22 +109,22 @@ void WaylandPointer::Button(void* data,
uint32_t button,
uint32_t state) {
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
- int flag;
+ int changed_button;
switch (button) {
case BTN_LEFT:
- flag = EF_LEFT_MOUSE_BUTTON;
+ changed_button = EF_LEFT_MOUSE_BUTTON;
break;
case BTN_MIDDLE:
- flag = EF_MIDDLE_MOUSE_BUTTON;
+ changed_button = EF_MIDDLE_MOUSE_BUTTON;
break;
case BTN_RIGHT:
- flag = EF_RIGHT_MOUSE_BUTTON;
+ changed_button = EF_RIGHT_MOUSE_BUTTON;
break;
case BTN_BACK:
- flag = EF_BACK_MOUSE_BUTTON;
+ changed_button = EF_BACK_MOUSE_BUTTON;
break;
case BTN_FORWARD:
- flag = EF_FORWARD_MOUSE_BUTTON;
+ changed_button = EF_FORWARD_MOUSE_BUTTON;
break;
default:
return;
@@ -116,17 +133,24 @@ void WaylandPointer::Button(void* data,
EventType type;
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
type = ET_MOUSE_PRESSED;
- pointer->flags_ |= flag;
+ pointer->flags_ |= changed_button;
pointer->connection_->set_serial(serial);
} else {
type = ET_MOUSE_RELEASED;
- pointer->flags_ &= ~flag;
+ pointer->flags_ &= ~changed_button;
+ }
+
+ if (pointer->window_with_pointer_focus_) {
+ pointer->window_with_pointer_focus_->set_has_implicit_grab(
+ HasAnyButtonFlag(pointer->flags_));
}
- int flags = pointer->GetFlagsWithKeyboardModifiers() | flag;
+ // MouseEvent's flags should contain the button that was released too.
+ const int flags = pointer->GetFlagsWithKeyboardModifiers() | changed_button;
MouseEvent event(type, gfx::Point(), gfx::Point(),
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time),
- flags, flag);
+ flags, changed_button);
+
event.set_location_f(pointer->location_);
event.set_root_location_f(pointer->location_);
pointer->callback_.Run(&event);
diff --git a/chromium/ui/ozone/platform/wayland/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/wayland_pointer.h
index 9550da69334..9515dfccdac 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_pointer.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
+#include "base/macros.h"
#include "ui/events/ozone/evdev/event_dispatch_callback.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/wayland_cursor.h"
@@ -12,6 +13,8 @@
namespace ui {
+class WaylandWindow;
+
class WaylandPointer {
public:
WaylandPointer(wl_pointer* pointer, const EventDispatchCallback& callback);
@@ -26,6 +29,10 @@ class WaylandPointer {
WaylandCursor* cursor() { return cursor_.get(); }
+ void reset_window_with_pointer_focus() {
+ window_with_pointer_focus_ = nullptr;
+ }
+
private:
// wl_pointer_listener
static void Enter(void* data,
@@ -60,11 +67,18 @@ class WaylandPointer {
wl::Object<wl_pointer> obj_;
EventDispatchCallback callback_;
gfx::PointF location_;
+ // Flags is a bitmask of EventFlags corresponding to the pointer/keyboard
+ // state.
int flags_ = 0;
// Keeps track of current modifiers. These are needed in order to properly
// update |flags_| with newest modifiers.
int keyboard_modifiers_ = 0;
+
+ // The window the mouse is over.
+ WaylandWindow* window_with_pointer_focus_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandPointer);
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/wayland_pointer_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
index ab2a8085d69..5c0e98a78d7 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
@@ -25,17 +25,17 @@ class WaylandPointerTest : public WaylandTest {
void SetUp() override {
WaylandTest::SetUp();
- wl_seat_send_capabilities(server.seat()->resource(),
+ wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_POINTER);
Sync();
- pointer = server.seat()->pointer.get();
- ASSERT_TRUE(pointer);
+ pointer_ = server_.seat()->pointer();
+ ASSERT_TRUE(pointer_);
}
protected:
- wl::MockPointer* pointer;
+ wl::MockPointer* pointer_;
private:
DISALLOW_COPY_AND_ASSIGN(WaylandPointerTest);
@@ -43,7 +43,7 @@ class WaylandPointerTest : public WaylandTest {
TEST_P(WaylandPointerTest, Leave) {
MockPlatformWindowDelegate other_delegate;
- WaylandWindow other_window(&other_delegate, connection.get(),
+ WaylandWindow other_window(&other_delegate, connection_.get(),
gfx::Rect(0, 0, 10, 10));
gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget;
EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_, _))
@@ -54,16 +54,16 @@ TEST_P(WaylandPointerTest, Leave) {
Sync();
wl::MockSurface* other_surface =
- server.GetObject<wl::MockSurface>(other_widget);
+ server_.GetObject<wl::MockSurface>(other_widget);
ASSERT_TRUE(other_surface);
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(), 0, 0);
- wl_pointer_send_leave(pointer->resource(), 2, surface->resource());
- wl_pointer_send_enter(pointer->resource(), 3, other_surface->resource(), 0,
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0);
+ wl_pointer_send_leave(pointer_->resource(), 2, surface_->resource());
+ wl_pointer_send_enter(pointer_->resource(), 3, other_surface->resource(), 0,
0);
- wl_pointer_send_button(pointer->resource(), 4, 1004, BTN_LEFT,
+ wl_pointer_send_button(pointer_->resource(), 4, 1004, BTN_LEFT,
WL_POINTER_BUTTON_STATE_PRESSED);
- EXPECT_CALL(delegate, DispatchEvent(_)).Times(1);
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
// Do an extra Sync() here so that we process the second enter event before we
// destroy |other_window|.
@@ -75,12 +75,13 @@ ACTION_P(CloneEvent, ptr) {
}
TEST_P(WaylandPointerTest, Motion) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(), 0, 0);
- wl_pointer_send_motion(pointer->resource(), 1002, wl_fixed_from_double(10.75),
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0);
+ wl_pointer_send_motion(pointer_->resource(), 1002,
+ wl_fixed_from_double(10.75),
wl_fixed_from_double(20.375));
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
Sync();
@@ -95,15 +96,15 @@ TEST_P(WaylandPointerTest, Motion) {
}
TEST_P(WaylandPointerTest, MotionDragged) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(), 0, 0);
- wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_MIDDLE,
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0);
+ wl_pointer_send_button(pointer_->resource(), 2, 1002, BTN_MIDDLE,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
- wl_pointer_send_motion(pointer->resource(), 1003, wl_fixed_from_int(400),
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ wl_pointer_send_motion(pointer_->resource(), 1003, wl_fixed_from_int(400),
wl_fixed_from_int(500));
Sync();
@@ -119,44 +120,59 @@ TEST_P(WaylandPointerTest, MotionDragged) {
}
TEST_P(WaylandPointerTest, ButtonPress) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(),
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(),
wl_fixed_from_int(200), wl_fixed_from_int(150));
- wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_RIGHT,
- WL_POINTER_BUTTON_STATE_PRESSED);
-
Sync();
- std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
- wl_pointer_send_button(pointer->resource(), 3, 1003, BTN_LEFT,
+ wl_pointer_send_button(pointer_->resource(), 2, 1002, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+ std::unique_ptr<Event> right_press_event;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .WillOnce(CloneEvent(&right_press_event));
+ Sync();
+ ASSERT_TRUE(right_press_event);
+ ASSERT_TRUE(right_press_event->IsMouseEvent());
+ auto* right_press_mouse_event = right_press_event->AsMouseEvent();
+ EXPECT_EQ(ET_MOUSE_PRESSED, right_press_mouse_event->type());
+ EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, right_press_mouse_event->button_flags());
+ EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON,
+ right_press_mouse_event->changed_button_flags());
+
+ std::unique_ptr<Event> left_press_event;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .WillOnce(CloneEvent(&left_press_event));
+ wl_pointer_send_button(pointer_->resource(), 3, 1003, BTN_LEFT,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
- ASSERT_TRUE(event);
- ASSERT_TRUE(event->IsMouseEvent());
- auto* mouse_event = event->AsMouseEvent();
- EXPECT_EQ(ET_MOUSE_PRESSED, mouse_event->type());
+ ASSERT_TRUE(left_press_event);
+ ASSERT_TRUE(left_press_event->IsMouseEvent());
+ auto* left_press_mouse_event = left_press_event->AsMouseEvent();
+ EXPECT_EQ(ET_MOUSE_PRESSED, left_press_mouse_event->type());
EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON,
- mouse_event->button_flags());
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, mouse_event->changed_button_flags());
- EXPECT_EQ(gfx::PointF(200, 150), mouse_event->location_f());
- EXPECT_EQ(gfx::PointF(200, 150), mouse_event->root_location_f());
+ left_press_mouse_event->button_flags());
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON,
+ left_press_mouse_event->changed_button_flags());
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON,
+ left_press_mouse_event->changed_button_flags());
+ EXPECT_EQ(gfx::PointF(200, 150), left_press_mouse_event->location_f());
+ EXPECT_EQ(gfx::PointF(200, 150), left_press_mouse_event->root_location_f());
}
TEST_P(WaylandPointerTest, ButtonRelease) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(),
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(),
wl_fixed_from_int(50), wl_fixed_from_int(50));
- wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_BACK,
+ wl_pointer_send_button(pointer_->resource(), 2, 1002, BTN_BACK,
WL_POINTER_BUTTON_STATE_PRESSED);
- wl_pointer_send_button(pointer->resource(), 3, 1003, BTN_LEFT,
+ wl_pointer_send_button(pointer_->resource(), 3, 1003, BTN_LEFT,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
- wl_pointer_send_button(pointer->resource(), 4, 1004, BTN_LEFT,
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ wl_pointer_send_button(pointer_->resource(), 4, 1004, BTN_LEFT,
WL_POINTER_BUTTON_STATE_RELEASED);
Sync();
@@ -173,17 +189,17 @@ TEST_P(WaylandPointerTest, ButtonRelease) {
}
TEST_P(WaylandPointerTest, AxisVertical) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(),
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(),
wl_fixed_from_int(0), wl_fixed_from_int(0));
- wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_RIGHT,
+ wl_pointer_send_button(pointer_->resource(), 2, 1002, BTN_RIGHT,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
// Wayland servers typically send a value of 10 per mouse wheel click.
- wl_pointer_send_axis(pointer->resource(), 1003,
+ wl_pointer_send_axis(pointer_->resource(), 1003,
WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(20));
Sync();
@@ -200,17 +216,17 @@ TEST_P(WaylandPointerTest, AxisVertical) {
}
TEST_P(WaylandPointerTest, AxisHorizontal) {
- wl_pointer_send_enter(pointer->resource(), 1, surface->resource(),
+ wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(),
wl_fixed_from_int(50), wl_fixed_from_int(75));
- wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_LEFT,
+ wl_pointer_send_button(pointer_->resource(), 2, 1002, BTN_LEFT,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
// Wayland servers typically send a value of 10 per mouse wheel click.
- wl_pointer_send_axis(pointer->resource(), 1003,
+ wl_pointer_send_axis(pointer_->resource(), 1003,
WL_POINTER_AXIS_HORIZONTAL_SCROLL,
wl_fixed_from_int(10));
diff --git a/chromium/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
index 2ee97407685..ac537496dc7 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
@@ -19,13 +19,13 @@ namespace ui {
class WaylandSurfaceFactoryTest : public WaylandTest {
public:
- WaylandSurfaceFactoryTest() : surface_factory(connection.get()) {}
+ WaylandSurfaceFactoryTest() : surface_factory(connection_.get()) {}
~WaylandSurfaceFactoryTest() override {}
void SetUp() override {
WaylandTest::SetUp();
- canvas = surface_factory.CreateCanvasForWidget(widget);
+ canvas = surface_factory.CreateCanvasForWidget(widget_);
ASSERT_TRUE(canvas);
}
@@ -41,11 +41,11 @@ TEST_P(WaylandSurfaceFactoryTest, Canvas) {
canvas->GetSurface();
canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15));
- Expectation damage = EXPECT_CALL(*surface, Damage(5, 10, 20, 15));
+ Expectation damage = EXPECT_CALL(*surface_, Damage(5, 10, 20, 15));
wl_resource* buffer_resource = nullptr;
- Expectation attach = EXPECT_CALL(*surface, Attach(_, 0, 0))
+ Expectation attach = EXPECT_CALL(*surface_, Attach(_, 0, 0))
.WillOnce(SaveArg<0>(&buffer_resource));
- EXPECT_CALL(*surface, Commit()).After(damage, attach);
+ EXPECT_CALL(*surface_, Commit()).After(damage, attach);
Sync();
@@ -65,11 +65,11 @@ TEST_P(WaylandSurfaceFactoryTest, CanvasResize) {
canvas->GetSurface();
canvas->PresentCanvas(gfx::Rect(0, 0, 100, 50));
- Expectation damage = EXPECT_CALL(*surface, Damage(0, 0, 100, 50));
+ Expectation damage = EXPECT_CALL(*surface_, Damage(0, 0, 100, 50));
wl_resource* buffer_resource = nullptr;
- Expectation attach = EXPECT_CALL(*surface, Attach(_, 0, 0))
+ Expectation attach = EXPECT_CALL(*surface_, Attach(_, 0, 0))
.WillOnce(SaveArg<0>(&buffer_resource));
- EXPECT_CALL(*surface, Commit()).After(damage, attach);
+ EXPECT_CALL(*surface_, Commit()).After(damage, attach);
Sync();
diff --git a/chromium/ui/ozone/platform/wayland/wayland_test.cc b/chromium/ui/ozone/platform/wayland/wayland_test.cc
index 7bc6c91e462..a56cbcb8a4f 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_test.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_test.cc
@@ -27,48 +27,48 @@ WaylandTest::WaylandTest() {
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
std::make_unique<StubKeyboardLayoutEngine>());
#endif
- connection.reset(new WaylandConnection);
- window = std::make_unique<WaylandWindow>(&delegate, connection.get(),
- gfx::Rect(0, 0, 800, 600));
+ connection_.reset(new WaylandConnection);
+ window_ = std::make_unique<WaylandWindow>(&delegate_, connection_.get(),
+ gfx::Rect(0, 0, 800, 600));
}
WaylandTest::~WaylandTest() {}
void WaylandTest::SetUp() {
- ASSERT_TRUE(server.Start(GetParam()));
- ASSERT_TRUE(connection->Initialize());
- EXPECT_CALL(delegate, OnAcceleratedWidgetAvailable(_, _))
- .WillOnce(SaveArg<0>(&widget));
- ASSERT_TRUE(window->Initialize());
- ASSERT_NE(widget, gfx::kNullAcceleratedWidget);
+ ASSERT_TRUE(server_.Start(GetParam()));
+ ASSERT_TRUE(connection_->Initialize());
+ EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_, _))
+ .WillOnce(SaveArg<0>(&widget_));
+ ASSERT_TRUE(window_->Initialize());
+ ASSERT_NE(widget_, gfx::kNullAcceleratedWidget);
// Wait for the client to flush all pending requests from initialization.
base::RunLoop().RunUntilIdle();
// Pause the server after it has responded to all incoming events.
- server.Pause();
+ server_.Pause();
- surface = server.GetObject<wl::MockSurface>(widget);
- ASSERT_TRUE(surface);
+ surface_ = server_.GetObject<wl::MockSurface>(widget_);
+ ASSERT_TRUE(surface_);
- initialized = true;
+ initialized_ = true;
}
void WaylandTest::TearDown() {
- if (initialized)
+ if (initialized_)
Sync();
}
void WaylandTest::Sync() {
// Resume the server, flushing its pending events.
- server.Resume();
+ server_.Resume();
// Wait for the client to finish processing these events.
base::RunLoop().RunUntilIdle();
// Pause the server, after it has finished processing any follow-up requests
// from the client.
- server.Pause();
+ server_.Pause();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/wayland_test.h b/chromium/ui/ozone/platform/wayland/wayland_test.h
index 80587745e1a..20f7dfa47ad 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_test.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_test.h
@@ -35,17 +35,17 @@ class WaylandTest : public ::testing::TestWithParam<uint32_t> {
void Sync();
private:
- bool initialized = false;
- base::MessageLoopForUI message_loop;
+ base::MessageLoopForUI message_loop_;
+ bool initialized_ = false;
protected:
- wl::FakeServer server;
- wl::MockSurface* surface;
+ wl::FakeServer server_;
+ wl::MockSurface* surface_;
- MockPlatformWindowDelegate delegate;
- std::unique_ptr<WaylandConnection> connection;
- std::unique_ptr<WaylandWindow> window;
- gfx::AcceleratedWidget widget = gfx::kNullAcceleratedWidget;
+ MockPlatformWindowDelegate delegate_;
+ std::unique_ptr<WaylandConnection> connection_;
+ std::unique_ptr<WaylandWindow> window_;
+ gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
private:
#if BUILDFLAG(USE_XKBCOMMON)
diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/wayland_touch.cc
index b8dc5437f79..9052eaf09b3 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_touch.cc
@@ -8,7 +8,6 @@
#include <wayland-client.h>
#include "base/files/scoped_file.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/ui_features.h"
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc
index c9afacb6a22..13a830f4baf 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc
@@ -33,13 +33,13 @@ class WaylandTouchTest : public WaylandTest {
void SetUp() override {
WaylandTest::SetUp();
- wl_seat_send_capabilities(server.seat()->resource(),
+ wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_TOUCH);
Sync();
- touch = server.seat()->touch.get();
- ASSERT_TRUE(touch);
+ touch_ = server_.seat()->touch();
+ ASSERT_TRUE(touch_);
}
protected:
@@ -51,7 +51,7 @@ class WaylandTouchTest : public WaylandTest {
EXPECT_EQ(event_type, key_event->type());
}
- wl::MockTouch* touch;
+ wl::MockTouch* touch_;
private:
DISALLOW_COPY_AND_ASSIGN(WaylandTouchTest);
@@ -59,21 +59,21 @@ class WaylandTouchTest : public WaylandTest {
TEST_P(WaylandTouchTest, KeypressAndMotion) {
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event));
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event));
- wl_touch_send_down(touch->resource(), 1, 0, surface->resource(), 0 /* id */,
+ wl_touch_send_down(touch_->resource(), 1, 0, surface_->resource(), 0 /* id */,
wl_fixed_from_int(50), wl_fixed_from_int(100));
Sync();
CheckEventType(ui::ET_TOUCH_PRESSED, event.get());
- wl_touch_send_motion(touch->resource(), 500, 0 /* id */,
+ wl_touch_send_motion(touch_->resource(), 500, 0 /* id */,
wl_fixed_from_int(100), wl_fixed_from_int(100));
Sync();
CheckEventType(ui::ET_TOUCH_MOVED, event.get());
- wl_touch_send_up(touch->resource(), 1, 1000, 0 /* id */);
+ wl_touch_send_up(touch_->resource(), 1, 1000, 0 /* id */);
Sync();
CheckEventType(ui::ET_TOUCH_RELEASED, event.get());
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.cc b/chromium/ui/ozone/platform/wayland/wayland_window.cc
index bed831b995c..6ebe40755d8 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.cc
@@ -7,11 +7,11 @@
#include <wayland-client.h>
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/events/event.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_pointer.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"
@@ -55,6 +55,8 @@ WaylandWindow::~WaylandWindow() {
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
connection_->RemoveWindow(surface_.id());
}
+ if (has_pointer_focus_)
+ connection_->pointer()->reset_window_with_pointer_focus();
}
// static
@@ -134,13 +136,21 @@ void WaylandWindow::SetTitle(const base::string16& title) {
}
void WaylandWindow::SetCapture() {
+ // Wayland does implicit grabs, and doesn't allow for explicit grabs. The
+ // exception to that seems to be popups, which can do a grab during show. Need
+ // to evaluate under what circumstances we need this.
NOTIMPLEMENTED();
}
void WaylandWindow::ReleaseCapture() {
+ // See comment in SetCapture() for details on wayland and grabs.
NOTIMPLEMENTED();
}
+bool WaylandWindow::HasCapture() const {
+ return has_implicit_grab_;
+}
+
void WaylandWindow::ToggleFullscreen() {
DCHECK(xdg_surface_);
@@ -234,8 +244,7 @@ PlatformImeController* WaylandWindow::GetPlatformImeController() {
return nullptr;
}
-bool WaylandWindow::CanDispatchEvent(const PlatformEvent& native_event) {
- Event* event = static_cast<Event*>(native_event);
+bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
if (event->IsMouseEvent())
return has_pointer_focus_;
if (event->IsKeyEvent())
@@ -268,14 +277,21 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
else
state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL;
- if (old_state != state_)
- delegate_->OnWindowStateChanged(state_);
+ // Update state before notifying delegate.
+ const bool did_active_change = is_active_ != is_activated;
+ is_active_ = is_activated;
// Rather than call SetBounds here for every configure event, just save the
// most recent bounds, and have WaylandConnection call ApplyPendingBounds
// when it has finished processing events. We may get many configure events
// in a row during an interactive resize, and only the last one matters.
SetPendingBounds(width, height);
+
+ if (old_state != state_)
+ delegate_->OnWindowStateChanged(state_);
+
+ if (did_active_change)
+ delegate_->OnActivationChanged(is_active_);
}
void WaylandWindow::OnCloseRequest() {
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.h b/chromium/ui/ozone/platform/wayland/wayland_window.h
index 8d205fa48b4..b534566ea63 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.h
@@ -43,6 +43,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Set whether this window has pointer focus and should dispatch mouse events.
void set_pointer_focus(bool focus) { has_pointer_focus_ = focus; }
+ bool has_pointer_focus() const { return has_pointer_focus_; }
// Set whether this window has keyboard focus and should dispatch key events.
void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; }
@@ -50,6 +51,13 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Set whether this window has touch focus and should dispatch touch events.
void set_touch_focus(bool focus) { has_touch_focus_ = focus; }
+ // Set whether this window has an implicit grab (often referred to as capture
+ // in Chrome code). Implicit grabs happen while a pointer is down.
+ void set_has_implicit_grab(bool value) { has_implicit_grab_ = value; }
+ bool has_implicit_grab() const { return has_implicit_grab_; }
+
+ bool is_active() const { return is_active_; }
+
// PlatformWindow
void Show() override;
void Hide() override;
@@ -60,6 +68,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
@@ -113,10 +122,13 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
bool has_pointer_focus_ = false;
bool has_keyboard_focus_ = false;
bool has_touch_focus_ = false;
+ bool has_implicit_grab_ = false;
// Stores current states of the window.
ui::PlatformWindowState state_;
+ bool is_active_ = false;
+
DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
};
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
index 2c2e2679a2a..77c1084fac8 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -2,6 +2,8 @@
// 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/wayland_window.h"
+
#include <wayland-server-core.h>
#include <xdg-shell-unstable-v5-server-protocol.h>
#include <xdg-shell-unstable-v6-server-protocol.h>
@@ -14,7 +16,6 @@
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/fake_server.h"
#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
using ::testing::Eq;
@@ -28,18 +29,18 @@ namespace ui {
class WaylandWindowTest : public WaylandTest {
public:
WaylandWindowTest()
- : test_mouse_event(ET_MOUSE_PRESSED,
- gfx::Point(10, 15),
- gfx::Point(10, 15),
- ui::EventTimeStampFromSeconds(123456),
- EF_LEFT_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON,
- EF_LEFT_MOUSE_BUTTON) {}
+ : test_mouse_event_(ET_MOUSE_PRESSED,
+ gfx::Point(10, 15),
+ gfx::Point(10, 15),
+ ui::EventTimeStampFromSeconds(123456),
+ EF_LEFT_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON,
+ EF_LEFT_MOUSE_BUTTON) {}
void SetUp() override {
WaylandTest::SetUp();
- xdg_surface = surface->xdg_surface.get();
- ASSERT_TRUE(xdg_surface);
+ xdg_surface_ = surface_->xdg_surface();
+ ASSERT_TRUE(xdg_surface_);
}
protected:
@@ -47,26 +48,26 @@ class WaylandWindowTest : public WaylandTest {
int height,
uint32_t serial,
struct wl_array* states) {
- if (!xdg_surface->xdg_toplevel) {
- xdg_surface_send_configure(xdg_surface->resource(), width, height, states,
- serial);
+ if (!xdg_surface_->xdg_toplevel()) {
+ xdg_surface_send_configure(xdg_surface_->resource(), width, height,
+ states, serial);
return;
}
// In xdg_shell_v6, both surfaces send serial configure event and toplevel
// surfaces send other data like states, heights and widths.
- zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
- ASSERT_TRUE(xdg_surface->xdg_toplevel);
- zxdg_toplevel_v6_send_configure(xdg_surface->xdg_toplevel->resource(),
+ zxdg_surface_v6_send_configure(xdg_surface_->resource(), serial);
+ ASSERT_TRUE(xdg_surface_->xdg_toplevel());
+ zxdg_toplevel_v6_send_configure(xdg_surface_->xdg_toplevel()->resource(),
width, height, states);
}
- // Depending on a shell version, xdg_surface or xdg_toplevel surface should
+ // Depending on a shell version, xdg_surface_ or xdg_toplevel surface should
// get the mock calls. This method decided, which surface to use.
wl::MockXdgSurface* GetXdgSurface() {
if (GetParam() == kXdgShellV5)
- return xdg_surface;
- return xdg_surface->xdg_toplevel.get();
+ return xdg_surface_;
+ return xdg_surface_->xdg_toplevel();
}
void SetWlArrayWithState(uint32_t state, wl_array* states) {
@@ -80,9 +81,9 @@ class WaylandWindowTest : public WaylandTest {
SetWlArrayWithState(XDG_SURFACE_STATE_ACTIVATED, states);
}
- wl::MockXdgSurface* xdg_surface;
+ wl::MockXdgSurface* xdg_surface_;
- MouseEvent test_mouse_event;
+ MouseEvent test_mouse_event_;
private:
DISALLOW_COPY_AND_ASSIGN(WaylandWindowTest);
@@ -90,25 +91,26 @@ class WaylandWindowTest : public WaylandTest {
TEST_P(WaylandWindowTest, SetTitle) {
EXPECT_CALL(*GetXdgSurface(), SetTitle(StrEq("hello")));
- window->SetTitle(base::ASCIIToUTF16("hello"));
+ window_->SetTitle(base::ASCIIToUTF16("hello"));
}
TEST_P(WaylandWindowTest, MaximizeAndRestore) {
wl_array states;
InitializeWlArrayWithActivatedState(&states);
- EXPECT_CALL(delegate,
+ EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED)));
SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
EXPECT_CALL(*GetXdgSurface(), SetMaximized());
- window->Maximize();
+ window_->Maximize();
SendConfigureEvent(0, 0, 1, &states);
Sync();
- EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
- window->Restore();
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 2, &states);
@@ -120,7 +122,8 @@ TEST_P(WaylandWindowTest, Minimize) {
wl_array_init(&states);
// Initialize to normal first.
- EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
SendConfigureEvent(0, 0, 1, &states);
Sync();
@@ -129,8 +132,8 @@ TEST_P(WaylandWindowTest, Minimize) {
// notified about the state, because 1) minimized state was set manually
// in WaylandWindow, and it has been confirmed in a back call from the server,
// which resulted in the same state as before.
- EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
- window->Minimize();
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Minimize();
// Reinitialize wl_array, which removes previous old states.
wl_array_init(&states);
SendConfigureEvent(0, 0, 2, &states);
@@ -144,15 +147,16 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
- EXPECT_CALL(delegate,
+ EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN)));
- window->ToggleFullscreen();
+ window_->ToggleFullscreen();
SendConfigureEvent(0, 0, 1, &states);
Sync();
EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
- EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
- window->Restore();
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 2, &states);
@@ -164,25 +168,26 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
InitializeWlArrayWithActivatedState(&states);
EXPECT_CALL(*GetXdgSurface(), SetMaximized());
- EXPECT_CALL(delegate,
+ EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED)));
- window->Maximize();
+ window_->Maximize();
SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
SendConfigureEvent(0, 0, 2, &states);
Sync();
EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
- EXPECT_CALL(delegate,
+ EXPECT_CALL(delegate_,
OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN)));
- window->ToggleFullscreen();
+ window_->ToggleFullscreen();
SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
SendConfigureEvent(0, 0, 3, &states);
Sync();
EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
- EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
- window->Restore();
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 4, &states);
@@ -190,26 +195,26 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
}
TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
- const gfx::Rect current_bounds = window->GetBounds();
+ const gfx::Rect current_bounds = window_->GetBounds();
wl_array states;
InitializeWlArrayWithActivatedState(&states);
const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
- window->Maximize();
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
+ window_->Maximize();
SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
&states);
Sync();
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
// Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
// Thus, using a toplevel object in XdgV6 case is not right thing. Use a
// surface here instead.
- EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
- current_bounds.height()));
- window->Restore();
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
+ current_bounds.height()));
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 2, &states);
@@ -217,26 +222,26 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
}
TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
- const gfx::Rect current_bounds = window->GetBounds();
+ const gfx::Rect current_bounds = window_->GetBounds();
wl_array states;
InitializeWlArrayWithActivatedState(&states);
const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds)));
- window->ToggleFullscreen();
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
+ window_->ToggleFullscreen();
SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 1,
&states);
Sync();
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
// Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
// Thus, using a toplevel object in XdgV6 case is not right thing. Use a
// surface here instead.
- EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
- current_bounds.height()));
- window->Restore();
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
+ current_bounds.height()));
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 2, &states);
@@ -244,29 +249,29 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
}
TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
- const gfx::Rect current_bounds = window->GetBounds();
+ const gfx::Rect current_bounds = window_->GetBounds();
wl_array states;
InitializeWlArrayWithActivatedState(&states);
const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
- window->Maximize();
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
+ window_->Maximize();
SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
&states);
Sync();
const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds)));
- window->ToggleFullscreen();
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
+ window_->ToggleFullscreen();
SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2,
&states);
Sync();
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
- window->Maximize();
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
+ window_->Maximize();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
@@ -274,13 +279,13 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
&states);
Sync();
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
// Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
// Thus, using a toplevel object in XdgV6 case is not right thing. Use a
// surface here instead.
- EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
- current_bounds.height()));
- window->Restore();
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
+ current_bounds.height()));
+ window_->Restore();
// Reinitialize wl_array, which removes previous old states.
InitializeWlArrayWithActivatedState(&states);
SendConfigureEvent(0, 0, 4, &states);
@@ -288,19 +293,19 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
}
TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
- const gfx::Rect initial_bounds = window->GetBounds();
+ 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(delegate, OnBoundsChanged(Eq(new_bounds)));
- window->SetBounds(new_bounds);
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(new_bounds)));
+ window_->SetBounds(new_bounds);
wl_array states;
InitializeWlArrayWithActivatedState(&states);
// First case is when Wayland sends a configure event with 0,0 height and
// widht.
- EXPECT_CALL(*xdg_surface,
+ EXPECT_CALL(*xdg_surface_,
SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height()))
.Times(2);
SendConfigureEvent(0, 0, 2, &states);
@@ -314,17 +319,22 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
}
TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
- EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event));
+ EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
}
TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) {
- window->set_pointer_focus(true);
- EXPECT_TRUE(window->CanDispatchEvent(&test_mouse_event));
+ // set_pointer_focus(true) requires a WaylandPointer.
+ wl_seat_send_capabilities(server_.seat()->resource(),
+ WL_SEAT_CAPABILITY_POINTER);
+ Sync();
+ ASSERT_TRUE(connection_->pointer());
+ window_->set_pointer_focus(true);
+ EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_));
}
TEST_P(WaylandWindowTest, CanDispatchMouseEventUnfocus) {
- window->set_pointer_focus(false);
- EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event));
+ EXPECT_FALSE(window_->has_pointer_focus());
+ EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
}
ACTION_P(CloneEvent, ptr) {
@@ -333,17 +343,47 @@ ACTION_P(CloneEvent, ptr) {
TEST_P(WaylandWindowTest, DispatchEvent) {
std::unique_ptr<Event> event;
- EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
- window->DispatchEvent(&test_mouse_event);
+ EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+ window_->DispatchEvent(&test_mouse_event_);
ASSERT_TRUE(event);
ASSERT_TRUE(event->IsMouseEvent());
auto* mouse_event = event->AsMouseEvent();
- EXPECT_EQ(mouse_event->location_f(), test_mouse_event.location_f());
- EXPECT_EQ(mouse_event->root_location_f(), test_mouse_event.root_location_f());
- EXPECT_EQ(mouse_event->time_stamp(), test_mouse_event.time_stamp());
- EXPECT_EQ(mouse_event->button_flags(), test_mouse_event.button_flags());
+ EXPECT_EQ(mouse_event->location_f(), test_mouse_event_.location_f());
+ EXPECT_EQ(mouse_event->root_location_f(),
+ test_mouse_event_.root_location_f());
+ EXPECT_EQ(mouse_event->time_stamp(), test_mouse_event_.time_stamp());
+ EXPECT_EQ(mouse_event->button_flags(), test_mouse_event_.button_flags());
EXPECT_EQ(mouse_event->changed_button_flags(),
- test_mouse_event.changed_button_flags());
+ test_mouse_event_.changed_button_flags());
+}
+
+TEST_P(WaylandWindowTest, HasCaptureUpdatedOnPointerEvents) {
+ wl_seat_send_capabilities(server_.seat()->resource(),
+ WL_SEAT_CAPABILITY_POINTER);
+
+ Sync();
+
+ wl::MockPointer* pointer = server_.seat()->pointer();
+ ASSERT_TRUE(pointer);
+
+ wl_pointer_send_enter(pointer->resource(), 1, surface_->resource(), 0, 0);
+ Sync();
+ EXPECT_FALSE(window_->HasCapture());
+
+ wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_LEFT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+ Sync();
+ EXPECT_TRUE(window_->HasCapture());
+
+ wl_pointer_send_motion(pointer->resource(), 1003, wl_fixed_from_int(400),
+ wl_fixed_from_int(500));
+ Sync();
+ EXPECT_TRUE(window_->HasCapture());
+
+ wl_pointer_send_button(pointer->resource(), 4, 1004, BTN_LEFT,
+ WL_POINTER_BUTTON_STATE_RELEASED);
+ Sync();
+ EXPECT_FALSE(window_->HasCapture());
}
TEST_P(WaylandWindowTest, ConfigureEvent) {
@@ -354,14 +394,14 @@ TEST_P(WaylandWindowTest, ConfigureEvent) {
// Make sure that the implementation does not call OnBoundsChanged for each
// configure event if it receives multiple in a row.
- EXPECT_CALL(delegate, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1500, 1000))));
+ EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1500, 1000))));
// Responding to a configure event, the window geometry in here must respect
// the sizing negotiations specified by the configure event.
- // |xdg_surface| must receive the following calls in both xdg_shell_v5 and
+ // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and
// xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by
- // xdg_toplevel in xdg_shell_v6 and by xdg_surface in xdg_shell_v5.
- EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, 1500, 1000)).Times(1);
- EXPECT_CALL(*xdg_surface, AckConfigure(13));
+ // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1500, 1000)).Times(1);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(13));
}
TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
@@ -372,11 +412,31 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
// call back with desired sizes. In this case, that's the actual size of
// the window.
SendConfigureEvent(0, 0, 14, &states);
- // |xdg_surface| must receive the following calls in both xdg_shell_v5 and
+ // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and
// xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by
- // xdg_toplevel in xdg_shell_v6 and by xdg_surface in xdg_shell_v5.
- EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, 800, 600));
- EXPECT_CALL(*xdg_surface, AckConfigure(14));
+ // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 800, 600));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(14));
+}
+
+TEST_P(WaylandWindowTest, OnActivationChanged) {
+ EXPECT_FALSE(window_->is_active());
+
+ {
+ wl_array states;
+ InitializeWlArrayWithActivatedState(&states);
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+ SendConfigureEvent(0, 0, 1, &states);
+ Sync();
+ EXPECT_TRUE(window_->is_active());
+ }
+
+ wl_array states;
+ wl_array_init(&states);
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
+ SendConfigureEvent(0, 0, 2, &states);
+ Sync();
+ EXPECT_FALSE(window_->is_active());
}
INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn
index e73f2cf063b..24d53e267a5 100644
--- a/chromium/ui/ozone/platform/x11/BUILD.gn
+++ b/chromium/ui/ozone/platform/x11/BUILD.gn
@@ -59,12 +59,19 @@ source_set("x11_unittests") {
testonly = true
sources = [
"x11_cursor_factory_ozone_unittest.cc",
+ "x11_window_ozone_unittest.cc",
]
deps = [
":x11",
+ "//testing/gmock",
"//testing/gtest",
+ "//ui/events:test_support",
+ "//ui/events/devices/x11",
+ "//ui/events/platform/x11",
"//ui/ozone:platform",
+ "//ui/ozone:test_support",
"//ui/ozone/common",
+ "//ui/platform_window/x11:x11",
]
}
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 476f69ff287..9dd37001e47 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -7,7 +7,6 @@
#include <memory>
#include <utility>
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/x/x11_util.h"
@@ -108,15 +107,18 @@ class OzonePlatformX11 : public OzonePlatform {
private:
// Performs initialization steps need by both UI and GPU.
void InitializeCommon(const InitParams& params) {
- // TODO(kylechar): Add DCHECK we only enter InitializeCommon() twice for
- // single process mode.
if (common_initialized_)
return;
- // Always initialze in multi-thread mode, since this is used only during
+ // Always initialize in multi-thread mode, since this is used only during
// development.
XInitThreads();
+ // If XOpenDisplay() 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(gfx::GetXDisplay()) << "Missing X server or $DISPLAY";
+
ui::SetDefaultX11ErrorHandlers();
common_initialized_ = true;
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
index 95ec3306ad3..b0207c19c71 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -4,7 +4,6 @@
#include "ui/ozone/platform/x11/x11_surface_factory.h"
-#include "base/memory/ptr_util.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc
index 494c43cd6f2..100bc2e793e 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc
@@ -13,14 +13,20 @@ X11WindowManagerOzone::X11WindowManagerOzone() : event_grabber_(nullptr) {}
X11WindowManagerOzone::~X11WindowManagerOzone() {}
void X11WindowManagerOzone::GrabEvents(X11WindowOzone* window) {
- if (event_grabber_ != window)
+ if (event_grabber_ == window)
return;
+
+ X11WindowOzone* old_grabber = event_grabber_;
+ if (old_grabber)
+ old_grabber->OnLostCapture();
+
event_grabber_ = window;
}
void X11WindowManagerOzone::UngrabEvents(X11WindowOzone* window) {
if (event_grabber_ != window)
return;
+ event_grabber_->OnLostCapture();
event_grabber_ = nullptr;
}
diff --git a/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h
index 884425c8571..81250ddf6ae 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h
@@ -16,11 +16,12 @@ class X11WindowManagerOzone {
X11WindowManagerOzone();
~X11WindowManagerOzone();
- // Tries to set a given X11WindowOzone as the recipient for events. It will
- // fail if there is already another X11WindowOzone as recipient.
+ // Sets a given X11WindowOzone as the recipient for events and calls
+ // OnLostCapture for another |event_grabber_| if it has been set previously.
void GrabEvents(X11WindowOzone* window);
- // Unsets a given X11WindowOzone as the recipient for events.
+ // Unsets a given X11WindowOzone as the recipient for events and calls
+ // OnLostCapture.
void UngrabEvents(X11WindowOzone* window);
// Gets the current X11WindowOzone recipient of mouse events.
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc
index 1ce459877dc..c3f17315009 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/point.h"
@@ -68,17 +69,33 @@ bool X11WindowOzone::DispatchXEvent(XEvent* xev) {
return true;
}
-bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& platform_event) {
+bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& event) {
return handle_next_event_;
}
-uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& platform_event) {
- // This is unfortunately needed otherwise events that depend on global state
- // (eg. double click) are broken.
- DispatchEventFromNativeUiEvent(
- platform_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
- base::Unretained(delegate())));
- return POST_DISPATCH_STOP_PROPAGATION;
+uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& event) {
+ if (!window_manager_->event_grabber() ||
+ window_manager_->event_grabber() == this) {
+ // This is unfortunately needed otherwise events that depend on global state
+ // (eg. double click) are broken.
+ DispatchEventFromNativeUiEvent(
+ event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
+ base::Unretained(delegate())));
+ return POST_DISPATCH_STOP_PROPAGATION;
+ }
+
+ if (event->IsLocatedEvent()) {
+ // Another X11WindowOzone has installed itself as capture. Translate the
+ // event's location and dispatch to the other.
+ ConvertEventLocationToTargetWindowLocation(
+ window_manager_->event_grabber()->GetBounds().origin(),
+ GetBounds().origin(), event->AsLocatedEvent());
+ }
+ return window_manager_->event_grabber()->DispatchEvent(event);
+}
+
+void X11WindowOzone::OnLostCapture() {
+ delegate()->OnLostCapture();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_ozone.h
index 48568ca420c..e1586341f19 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.h
@@ -24,6 +24,9 @@ class X11WindowOzone : public X11WindowBase,
const gfx::Rect& bounds);
~X11WindowOzone() override;
+ // Called by |window_manager_| once capture is set to another X11WindowOzone.
+ void OnLostCapture();
+
// PlatformWindow:
void PrepareForShutdown() override;
void SetCapture() override;
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
new file mode 100644
index 00000000000..f770a61a243
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -0,0 +1,150 @@
+// 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/ozone/platform/x11/x11_window_ozone.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/devices/x11/touch_factory_x11.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/x11/x11_event_source_libevent.h"
+#include "ui/events/test/events_test_utils_x11.h"
+#include "ui/ozone/platform/x11/x11_window_manager_ozone.h"
+#include "ui/ozone/test/mock_platform_window_delegate.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+namespace {
+
+using ::testing::Eq;
+using ::testing::_;
+
+constexpr int kPointerDeviceId = 1;
+
+ACTION_P(StoreWidget, widget_ptr) {
+ *widget_ptr = arg0;
+}
+
+ACTION_P(CloneEvent, event_ptr) {
+ *event_ptr = Event::Clone(*arg0);
+}
+
+} // namespace
+
+class X11WindowOzoneTest : public testing::Test {
+ public:
+ X11WindowOzoneTest()
+ : task_env_(std::make_unique<base::test::ScopedTaskEnvironment>(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI)) {}
+
+ ~X11WindowOzoneTest() override = default;
+
+ void SetUp() override {
+ XDisplay* display = gfx::GetXDisplay();
+ event_source_ = std::make_unique<X11EventSourceLibevent>(display);
+ window_manager_ = std::make_unique<X11WindowManagerOzone>();
+
+ TouchFactory::GetInstance()->SetPointerDeviceForTest({kPointerDeviceId});
+ }
+
+ protected:
+ std::unique_ptr<PlatformWindow> CreatePlatformWindow(
+ MockPlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds,
+ gfx::AcceleratedWidget* widget) {
+ EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_, _))
+ .WillOnce(StoreWidget(widget));
+ auto window = std::make_unique<X11WindowOzone>(window_manager_.get(),
+ delegate, bounds);
+ return std::move(window);
+ }
+
+ void DispatchXEvent(XEvent* event, gfx::AcceleratedWidget widget) {
+ DCHECK_EQ(GenericEvent, event->type);
+ XIDeviceEvent* device_event =
+ static_cast<XIDeviceEvent*>(event->xcookie.data);
+ device_event->event = widget;
+ event_source_->ProcessXEvent(event);
+ }
+
+ private:
+ std::unique_ptr<base::test::ScopedTaskEnvironment> task_env_;
+ std::unique_ptr<X11WindowManagerOzone> window_manager_;
+ std::unique_ptr<X11EventSourceLibevent> event_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11WindowOzoneTest);
+};
+
+// This test ensures that events are handled by a right target(widget).
+TEST_F(X11WindowOzoneTest, SendPlatformEventToRightTarget) {
+ MockPlatformWindowDelegate delegate;
+ gfx::AcceleratedWidget widget;
+ constexpr gfx::Rect bounds(30, 80, 800, 600);
+ auto window = CreatePlatformWindow(&delegate, bounds, &widget);
+
+ ScopedXI2Event xi_event;
+ xi_event.InitGenericButtonEvent(kPointerDeviceId, ET_MOUSE_PRESSED,
+ gfx::Point(218, 290), EF_NONE);
+
+ // First check events can be received by a target window.
+ std::unique_ptr<Event> event;
+ EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+ DispatchXEvent(xi_event, widget);
+ EXPECT_EQ(ET_MOUSE_PRESSED, event->type());
+ testing::Mock::VerifyAndClearExpectations(&delegate);
+
+ MockPlatformWindowDelegate delegate_2;
+ gfx::AcceleratedWidget widget_2;
+ gfx::Rect bounds_2(525, 155, 296, 407);
+
+ auto window_2 = CreatePlatformWindow(&delegate_2, bounds_2, &widget_2);
+
+ // Check event goes to right target without capture being set.
+ event.reset();
+ EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
+ EXPECT_CALL(delegate_2, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+ DispatchXEvent(xi_event, widget_2);
+ EXPECT_EQ(ET_MOUSE_PRESSED, event->type());
+
+ EXPECT_CALL(delegate, OnClosed()).Times(1);
+ EXPECT_CALL(delegate_2, OnClosed()).Times(1);
+}
+
+// This test case ensures that events are consumed by a window with explicit
+// capture, even though the event is sent to other window.
+TEST_F(X11WindowOzoneTest, SendPlatformEventToCapturedWindow) {
+ MockPlatformWindowDelegate delegate;
+ gfx::AcceleratedWidget widget;
+ constexpr gfx::Rect bounds(30, 80, 800, 600);
+ EXPECT_CALL(delegate, OnClosed()).Times(1);
+ auto window = CreatePlatformWindow(&delegate, bounds, &widget);
+
+ MockPlatformWindowDelegate delegate_2;
+ gfx::AcceleratedWidget widget_2;
+ gfx::Rect bounds_2(525, 155, 296, 407);
+ EXPECT_CALL(delegate_2, OnClosed()).Times(1);
+ auto window_2 = CreatePlatformWindow(&delegate_2, bounds_2, &widget_2);
+
+ ScopedXI2Event xi_event;
+ xi_event.InitGenericButtonEvent(kPointerDeviceId, ET_MOUSE_PRESSED,
+ gfx::Point(218, 290), EF_NONE);
+
+ // Set capture to the second window, but send an event to another window
+ // target. The event must have its location converted and received by the
+ // captured window instead.
+ window_2->SetCapture();
+ std::unique_ptr<Event> event;
+ EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
+ EXPECT_CALL(delegate_2, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+ DispatchXEvent(xi_event, widget);
+ EXPECT_EQ(ET_MOUSE_PRESSED, event->type());
+ EXPECT_EQ(gfx::Point(-277, 215), event->AsLocatedEvent()->location());
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc
index 110f816c557..7d6428b48d8 100644
--- a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc
+++ b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc
@@ -4,50 +4,17 @@
#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
-#include <memory>
-
-#include "base/memory/singleton.h"
#include "base/trace_event/trace_event.h"
-#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/ozone/platform_object.h"
#include "ui/ozone/platform_selection.h"
namespace ui {
-namespace {
-
-// Thread-safe owner of the gfx::ClientNativePixmapFactory. Not a LazyInstance
-// because it uses PlatformObject<>::Create() for factory construction.
-// TODO(jamescook|spang): This exists to solve a startup race for chrome with
-// mash http://crbug.com/807781. Removing the factory entirely would be better,
-// with something like http://crrev.com/c/899949.
-class PixmapFactorySingleton {
- public:
- static PixmapFactorySingleton* GetInstance() {
- return base::Singleton<PixmapFactorySingleton>::get();
- }
-
- private:
- friend struct base::DefaultSingletonTraits<PixmapFactorySingleton>;
-
- PixmapFactorySingleton() {
- TRACE_EVENT1("ozone", "CreateClientNativePixmapFactoryOzone", "platform",
- GetOzonePlatformName());
- pixmap_factory_ = PlatformObject<gfx::ClientNativePixmapFactory>::Create();
- gfx::ClientNativePixmapFactory::SetInstance(pixmap_factory_.get());
- }
-
- std::unique_ptr<gfx::ClientNativePixmapFactory> pixmap_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PixmapFactorySingleton);
-};
-
-} // namespace
-void CreateClientNativePixmapFactoryOzone() {
- // Multiple threads may race to create the factory (e.g. when the UI service
- // and ash service are running in the same process). Create the object as a
- // side effect of a thread-safe singleton.
- PixmapFactorySingleton::GetInstance();
+std::unique_ptr<gfx::ClientNativePixmapFactory>
+CreateClientNativePixmapFactoryOzone() {
+ TRACE_EVENT1("ozone", "CreateClientNativePixmapFactoryOzone", "platform",
+ GetOzonePlatformName());
+ return PlatformObject<gfx::ClientNativePixmapFactory>::Create();
}
} // namespace ui
diff --git a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h
index 29d6b5019e4..744e868ad85 100644
--- a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h
+++ b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h
@@ -5,14 +5,13 @@
#ifndef UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_
#define UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_
+#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/ozone/ozone_export.h"
namespace ui {
-// Creates a factory for pixmaps that can use be transported from the client to
-// the GPU process using a low-level ozone-provided platform specific mechanism.
-// The factory is installed as the gfx::ClientNativePixmapFactory instance.
-OZONE_EXPORT void CreateClientNativePixmapFactoryOzone();
+OZONE_EXPORT std::unique_ptr<gfx::ClientNativePixmapFactory>
+CreateClientNativePixmapFactoryOzone();
} // namespace ui
diff --git a/chromium/ui/ozone/public/interfaces/BUILD.gn b/chromium/ui/ozone/public/interfaces/BUILD.gn
index b9e7663b08c..ec7f11f2836 100644
--- a/chromium/ui/ozone/public/interfaces/BUILD.gn
+++ b/chromium/ui/ozone/public/interfaces/BUILD.gn
@@ -12,7 +12,7 @@ mojom("interfaces") {
]
public_deps = [
- "//mojo/common:common_custom_types",
+ "//mojo/public/mojom/base",
"//skia/public/interfaces:interfaces",
"//ui/display/mojo:interfaces",
"//ui/gfx/geometry/mojo",
diff --git a/chromium/ui/ozone/public/interfaces/drm_device.mojom b/chromium/ui/ozone/public/interfaces/drm_device.mojom
index eede42437b0..48ea6df2d89 100644
--- a/chromium/ui/ozone/public/interfaces/drm_device.mojom
+++ b/chromium/ui/ozone/public/interfaces/drm_device.mojom
@@ -4,8 +4,8 @@
module ui.ozone.mojom;
-import "mojo/common/file.mojom";
-import "mojo/common/file_path.mojom";
+import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/file_path.mojom";
import "ui/display/mojo/display_constants.mojom";
import "ui/display/mojo/display_mode.mojom";
import "ui/display/mojo/display_snapshot.mojom";
@@ -46,11 +46,11 @@ interface DrmDevice {
(array<display.mojom.DisplaySnapshot> display_snapshots);
// Transfers ownership of a DRM device to the GPU process.
- AddGraphicsDevice(mojo.common.mojom.FilePath path,
- mojo.common.mojom.File file);
+ AddGraphicsDevice(mojo_base.mojom.FilePath path,
+ mojo_base.mojom.File file);
// Instructs the GPU to abandon a DRM device.
- RemoveGraphicsDevice(mojo.common.mojom.FilePath path);
+ RemoveGraphicsDevice(mojo_base.mojom.FilePath path);
// Instructs the GPU to disable a DRM device.
DisableNativeDisplay(int64 display_id) => (int64 display_id, bool success);
diff --git a/chromium/ui/ozone/public/ozone_gpu_test_helper.cc b/chromium/ui/ozone/public/ozone_gpu_test_helper.cc
index cc89a0e3cac..3ade4fe580f 100644
--- a/chromium/ui/ozone/public/ozone_gpu_test_helper.cc
+++ b/chromium/ui/ozone/public/ozone_gpu_test_helper.cc
@@ -5,6 +5,7 @@
#include "ui/ozone/public/ozone_gpu_test_helper.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ipc/ipc_listener.h"
@@ -55,7 +56,7 @@ class FakeGpuProcess : public IPC::Channel {
// IPC::Channel implementation:
bool Send(IPC::Message* msg) override {
ui_task_runner_->PostTask(
- FROM_HERE, base::Bind(&DispatchToGpuPlatformSupportHostTask, msg));
+ FROM_HERE, base::BindOnce(&DispatchToGpuPlatformSupportHostTask, msg));
return true;
}
@@ -109,16 +110,24 @@ bool OzoneGpuTestHelper::Initialize(
fake_gpu_process_.reset(new FakeGpuProcess(ui_task_runner));
io_helper_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeGpuProcess::InitOnIO,
- base::Unretained(fake_gpu_process_.get())));
+ FROM_HERE, base::BindOnce(&FakeGpuProcess::InitOnIO,
+ base::Unretained(fake_gpu_process_.get())));
fake_gpu_process_host_.reset(new FakeGpuProcessHost(
ui_task_runner, io_helper_thread_->task_runner()));
io_helper_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeGpuProcessHost::InitOnIO,
- base::Unretained(fake_gpu_process_host_.get())));
+ FROM_HERE,
+ base::BindOnce(&FakeGpuProcessHost::InitOnIO,
+ base::Unretained(fake_gpu_process_host_.get())));
io_helper_thread_->FlushForTesting();
+ // Give the UI thread a chance to run any tasks posted from the IO thread
+ // after the GPU process is launched. This is needed for Ozone DRM, see
+ // https://crbug.com/830233.
+ base::RunLoop run_loop;
+ ui_task_runner->PostTask(FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+
return true;
}
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index 58c114ba430..2457d0b89e2 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -42,8 +42,11 @@ void OzonePlatform::InitializeForUI(const InitParams& args) {
EnsureInstance();
if (g_platform_initialized_ui)
return;
- g_platform_initialized_ui = true;
instance_->InitializeUI(args);
+ {
+ base::AutoLock lock(GetOzoneInstanceLock());
+ g_platform_initialized_ui = true;
+ }
// This is deliberately created after initializing so that the platform can
// create its own version of DDM.
DeviceDataManager::CreateInstance();
@@ -56,8 +59,11 @@ void OzonePlatform::InitializeForGPU(const InitParams& args) {
EnsureInstance();
if (g_platform_initialized_gpu)
return;
- g_platform_initialized_gpu = true;
instance_->InitializeGPU(args);
+ {
+ base::AutoLock lock(GetOzoneInstanceLock());
+ g_platform_initialized_gpu = true;
+ }
if (!args.single_process && !instance_callback.Get().is_null())
std::move(instance_callback.Get()).Run(instance_);
}
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index f715a6af03a..008e2c20d29 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -13,7 +13,6 @@
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/events/system_input_injector.h"
#include "ui/ozone/ozone_export.h"
-//#include "ui/ozone/public/interfaces/drm_device.mojom.h"
namespace display {
class NativeDisplayDelegate;
@@ -78,9 +77,9 @@ class OZONE_EXPORT OzonePlatform {
// split between a host and viz specific portion.
bool single_process = false;
- // Setting this to true indicates that the platform implementation should
- // use mojo. Setting this to true requires calling |AddInterfaces|
- // afterwards in the Viz process and providing a connector as part
+ // Setting this to true indicates that the platform implementation should
+ // use mojo. Setting this to true requires calling |AddInterfaces|
+ // afterwards in the Viz process and providing a connector as part.
bool using_mojo = false;
};
diff --git a/chromium/ui/platform_window/android/platform_window_android.cc b/chromium/ui/platform_window/android/platform_window_android.cc
index c32b24a3dac..ed53df532b3 100644
--- a/chromium/ui/platform_window/android/platform_window_android.cc
+++ b/chromium/ui/platform_window/android/platform_window_android.cc
@@ -196,6 +196,11 @@ void PlatformWindowAndroid::ReleaseCapture() {
NOTIMPLEMENTED();
}
+bool PlatformWindowAndroid::HasCapture() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
void PlatformWindowAndroid::ToggleFullscreen() {
NOTIMPLEMENTED();
}
diff --git a/chromium/ui/platform_window/android/platform_window_android.h b/chromium/ui/platform_window/android/platform_window_android.h
index 599ff71883f..803ab18de84 100644
--- a/chromium/ui/platform_window/android/platform_window_android.h
+++ b/chromium/ui/platform_window/android/platform_window_android.h
@@ -71,6 +71,7 @@ class ANDROID_WINDOW_EXPORT PlatformWindowAndroid : public PlatformWindow {
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
diff --git a/chromium/ui/platform_window/platform_window.h b/chromium/ui/platform_window/platform_window.h
index bd8dbb01ef9..1af4694264a 100644
--- a/chromium/ui/platform_window/platform_window.h
+++ b/chromium/ui/platform_window/platform_window.h
@@ -11,6 +11,7 @@
#include "ui/base/cursor/cursor.h"
namespace gfx {
+class Point;
class Rect;
}
@@ -44,6 +45,7 @@ class PlatformWindow {
virtual void SetCapture() = 0;
virtual void ReleaseCapture() = 0;
+ virtual bool HasCapture() const = 0;
virtual void ToggleFullscreen() = 0;
virtual void Maximize() = 0;
diff --git a/chromium/ui/platform_window/stub/stub_window.cc b/chromium/ui/platform_window/stub/stub_window.cc
index e646ca49792..d5fc54cca11 100644
--- a/chromium/ui/platform_window/stub/stub_window.cc
+++ b/chromium/ui/platform_window/stub/stub_window.cc
@@ -53,6 +53,10 @@ void StubWindow::SetCapture() {
void StubWindow::ReleaseCapture() {
}
+bool StubWindow::HasCapture() const {
+ return false;
+}
+
void StubWindow::ToggleFullscreen() {
}
diff --git a/chromium/ui/platform_window/stub/stub_window.h b/chromium/ui/platform_window/stub/stub_window.h
index fa01974c31f..c94a8473b7c 100644
--- a/chromium/ui/platform_window/stub/stub_window.h
+++ b/chromium/ui/platform_window/stub/stub_window.h
@@ -37,6 +37,7 @@ class STUB_WINDOW_EXPORT StubWindow : public PlatformWindow {
void SetCapture() override;
void ReleaseCapture() override;
void ToggleFullscreen() override;
+ bool HasCapture() const override;
void Maximize() override;
void Minimize() override;
void Restore() override;
diff --git a/chromium/ui/platform_window/win/win_window.cc b/chromium/ui/platform_window/win/win_window.cc
index 2f32390a5f5..39fd290bb0c 100644
--- a/chromium/ui/platform_window/win/win_window.cc
+++ b/chromium/ui/platform_window/win/win_window.cc
@@ -101,15 +101,19 @@ void WinWindow::SetTitle(const base::string16& title) {
}
void WinWindow::SetCapture() {
- if (::GetCapture() != hwnd())
+ if (!HasCapture())
::SetCapture(hwnd());
}
void WinWindow::ReleaseCapture() {
- if (::GetCapture() == hwnd())
+ if (HasCapture())
::ReleaseCapture();
}
+bool WinWindow::HasCapture() const {
+ return ::GetCapture() == hwnd();
+}
+
void WinWindow::ToggleFullscreen() {}
void WinWindow::Maximize() {}
diff --git a/chromium/ui/platform_window/win/win_window.h b/chromium/ui/platform_window/win/win_window.h
index c6774fde675..c2f7c224c6a 100644
--- a/chromium/ui/platform_window/win/win_window.h
+++ b/chromium/ui/platform_window/win/win_window.h
@@ -36,6 +36,7 @@ class WIN_WINDOW_EXPORT WinWindow : public PlatformWindow,
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
diff --git a/chromium/ui/platform_window/x11/x11_window_base.cc b/chromium/ui/platform_window/x11/x11_window_base.cc
index 75cc3eef6ab..b6c4214e1f1 100644
--- a/chromium/ui/platform_window/x11/x11_window_base.cc
+++ b/chromium/ui/platform_window/x11/x11_window_base.cc
@@ -224,6 +224,10 @@ void X11WindowBase::SetCapture() {}
void X11WindowBase::ReleaseCapture() {}
+bool X11WindowBase::HasCapture() const {
+ return false;
+}
+
void X11WindowBase::ToggleFullscreen() {
ui::SetWMSpecState(xwindow_, !IsFullscreen(),
gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"), x11::None);
diff --git a/chromium/ui/platform_window/x11/x11_window_base.h b/chromium/ui/platform_window/x11/x11_window_base.h
index b419dc19e8f..1a062b9290d 100644
--- a/chromium/ui/platform_window/x11/x11_window_base.h
+++ b/chromium/ui/platform_window/x11/x11_window_base.h
@@ -39,6 +39,7 @@ class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow {
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
+ bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
diff --git a/chromium/ui/resources/BUILD.gn b/chromium/ui/resources/BUILD.gn
index 8286ba501b5..c9ec04a2aea 100644
--- a/chromium/ui/resources/BUILD.gn
+++ b/chromium/ui/resources/BUILD.gn
@@ -5,7 +5,7 @@
import("//build/config/jumbo.gni")
import("//tools/grit/grit_rule.gni")
import("//tools/grit/repack.gni")
-import("//ui/base/ui_features.gni")
+import("//ui/webui/webui_features.gni")
group("resources") {
public_deps = [
@@ -191,7 +191,7 @@ repack("repack_ui_test_pak_100_percent") {
]
if (!is_ios) {
- deps += [ "//third_party/WebKit/public:resources_grit" ]
+ deps += [ "//third_party/blink/public:resources_grit" ]
}
if (!is_mac) {
@@ -208,7 +208,7 @@ repack("repack_ui_test_pak_100_percent") {
if (toolkit_views) {
deps += [ "//ui/views/resources" ]
sources += [
- "$root_gen_dir/blink/public/resources/blink_resources.pak",
+ "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
"$root_gen_dir/ui/views/resources/views_resources_100_percent.pak",
]
}
diff --git a/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png
new file mode 100644
index 00000000000..a5750ab283e
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/emoji_menu_item.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png
new file mode 100644
index 00000000000..f490a52c25f
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/emoji_menu_item.png
Binary files differ
diff --git a/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png b/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png
new file mode 100644
index 00000000000..10851aa55af
--- /dev/null
+++ b/chromium/ui/resources/default_300_percent/common/emoji_menu_item.png
Binary files differ
diff --git a/chromium/ui/resources/ui_resources.grd b/chromium/ui/resources/ui_resources.grd
index 10be1c5aa10..6d38ed3f886 100644
--- a/chromium/ui/resources/ui_resources.grd
+++ b/chromium/ui/resources/ui_resources.grd
@@ -108,6 +108,7 @@
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED" file="common/easy_unlock_unlocked.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_HOVER" file="common/easy_unlock_unlocked_hover.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_PRESSED" file="common/easy_unlock_unlocked_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_EMOJI_FAVICON" file="common/emoji_menu_item.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED" file="common/folder_closed.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED_RTL" file="common/folder_closed_rtl.png" />
<if expr="is_macosx">
diff --git a/chromium/ui/shell_dialogs/BUILD.gn b/chromium/ui/shell_dialogs/BUILD.gn
index e5018b276b1..80b4c176b1c 100644
--- a/chromium/ui/shell_dialogs/BUILD.gn
+++ b/chromium/ui/shell_dialogs/BUILD.gn
@@ -89,6 +89,8 @@ if (is_mac) {
mac_framework_bundle("shell_dialogs_unittests_bundle") {
testonly = true
+ framework_version = "S"
+ framework_contents = [ "Resources" ]
info_plist = "//ui/base/test/framework-Info.plist"
deps = [
":shell_dialogs_unittests_xibs",
diff --git a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
index 9ccd1bbc456..ab67062109f 100644
--- a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
@@ -64,6 +64,7 @@ void BaseShellDialogImpl::DisableOwner(HWND owner) {
// static
base::Thread* BaseShellDialogImpl::CreateDialogThread() {
base::Thread* thread = new base::Thread("Chrome_ShellDialogThread");
+ // Many shell dialogs require a COM Single-Threaded Apartment (STA) to run.
thread->init_com_with_mta(false);
bool started = thread->Start();
DCHECK(started);
diff --git a/chromium/ui/shell_dialogs/run_all_unittests.cc b/chromium/ui/shell_dialogs/run_all_unittests.cc
index 6b5b9bf19fb..90123181653 100644
--- a/chromium/ui/shell_dialogs/run_all_unittests.cc
+++ b/chromium/ui/shell_dialogs/run_all_unittests.cc
@@ -68,7 +68,7 @@ void ShellDialogsTestSuite::Shutdown() {
int main(int argc, char** argv) {
ShellDialogsTestSuite test_suite(argc, argv);
- return base::LaunchUnitTests(
- argc, argv,
- base::Bind(&ShellDialogsTestSuite::Run, base::Unretained(&test_suite)));
+ return base::LaunchUnitTests(argc, argv,
+ base::BindOnce(&ShellDialogsTestSuite::Run,
+ base::Unretained(&test_suite)));
}
diff --git a/chromium/ui/shell_dialogs/select_file_dialog.cc b/chromium/ui/shell_dialogs/select_file_dialog.cc
index 9b60383e547..70163ef65e1 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog.cc
@@ -115,7 +115,7 @@ void SelectFileDialog::SelectFile(
// that the listener is called asynchronously.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&SelectFileDialog::CancelFileSelection, this, params));
+ base::BindOnce(&SelectFileDialog::CancelFileSelection, this, params));
return;
}
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.cc b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
index be73a0677db..edbceef44b6 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
@@ -289,6 +289,7 @@ class SelectFileDialogImpl : public ui::SelectFileDialog,
// semantics for input paramaters as RunOpenFileDialog.
bool RunOpenMultiFileDialog(const std::wstring& title,
const std::wstring& filter,
+ const base::FilePath& initial_path,
HWND owner,
std::vector<base::FilePath>* paths);
@@ -344,8 +345,8 @@ void SelectFileDialogImpl::SelectFileImpl(
default_extension, BeginRun(owner),
owner, params);
execute_params.run_state.dialog_thread->task_runner()->PostTask(
- FROM_HERE, base::Bind(&SelectFileDialogImpl::ExecuteSelectFile, this,
- execute_params));
+ FROM_HERE, base::BindOnce(&SelectFileDialogImpl::ExecuteSelectFile, this,
+ execute_params));
}
bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
@@ -387,23 +388,25 @@ void SelectFileDialogImpl::ExecuteSelectFile(
params.run_state.owner, &path);
} else if (params.type == SELECT_OPEN_MULTI_FILE) {
std::vector<base::FilePath> paths;
- if (RunOpenMultiFileDialog(params.title, filter,
+ if (RunOpenMultiFileDialog(params.title, filter, path,
params.run_state.owner, &paths)) {
params.ui_task_runner->PostTask(
- FROM_HERE, base::Bind(&SelectFileDialogImpl::MultiFilesSelected, this,
- paths, params.params, params.run_state));
+ FROM_HERE,
+ base::BindOnce(&SelectFileDialogImpl::MultiFilesSelected, this, paths,
+ params.params, params.run_state));
return;
}
}
if (success) {
params.ui_task_runner->PostTask(
- FROM_HERE, base::Bind(&SelectFileDialogImpl::FileSelected, this, path,
- filter_index, params.params, params.run_state));
+ FROM_HERE,
+ base::BindOnce(&SelectFileDialogImpl::FileSelected, this, path,
+ filter_index, params.params, params.run_state));
} else {
params.ui_task_runner->PostTask(
- FROM_HERE, base::Bind(&SelectFileDialogImpl::FileNotSelected, this,
- params.params, params.run_state));
+ FROM_HERE, base::BindOnce(&SelectFileDialogImpl::FileNotSelected, this,
+ params.params, params.run_state));
}
}
@@ -597,13 +600,12 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(
return result;
}
-bool SelectFileDialogImpl::RunOpenFileDialog(
- const std::wstring& title,
- const std::wstring& filter,
- HWND owner,
- base::FilePath* path) {
- // We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
- // without having to close Chrome first.
+bool SelectFileDialogImpl::RunOpenFileDialog(const std::wstring& title,
+ const std::wstring& filter,
+ HWND owner,
+ base::FilePath* path) {
+ // We use OFN_NOCHANGEDIR so that the user can rename or delete the
+ // directory without having to close Chrome first.
ui::win::OpenFileName ofn(owner, OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR);
if (!path->empty()) {
if (IsDirectory(*path))
@@ -625,6 +627,7 @@ bool SelectFileDialogImpl::RunOpenFileDialog(
bool SelectFileDialogImpl::RunOpenMultiFileDialog(
const std::wstring& title,
const std::wstring& filter,
+ const base::FilePath& initial_path,
HWND owner,
std::vector<base::FilePath>* paths) {
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
@@ -633,7 +636,12 @@ bool SelectFileDialogImpl::RunOpenMultiFileDialog(
OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
OFN_EXPLORER | OFN_HIDEREADONLY |
OFN_ALLOWMULTISELECT | OFN_NOCHANGEDIR);
-
+ if (!initial_path.empty()) {
+ if (IsDirectory(initial_path))
+ ofn.SetInitialSelection(initial_path, base::FilePath());
+ else
+ ofn.SetInitialSelection(initial_path.DirName(), base::FilePath());
+ }
if (!filter.empty())
ofn.GetOPENFILENAME()->lpstrFilter = filter.c_str();
diff --git a/chromium/ui/snapshot/BUILD.gn b/chromium/ui/snapshot/BUILD.gn
index f2379880561..840df0e7452 100644
--- a/chromium/ui/snapshot/BUILD.gn
+++ b/chromium/ui/snapshot/BUILD.gn
@@ -100,7 +100,7 @@ test("snapshot_unittests") {
":snapshot",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/base",
diff --git a/chromium/ui/snapshot/snapshot_aura.cc b/chromium/ui/snapshot/snapshot_aura.cc
index 8e3d10a794a..a5b80a03c42 100644
--- a/chromium/ui/snapshot/snapshot_aura.cc
+++ b/chromium/ui/snapshot/snapshot_aura.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/memory/ptr_util.h"
#include "base/task_runner_util.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -59,7 +58,7 @@ static void FinishedAsyncCopyRequest(
aura::Window* window = tracker->windows()[0];
MakeAsyncCopyRequest(
window->layer(), source_rect,
- base::BindOnce(&FinishedAsyncCopyRequest, base::Passed(&tracker),
+ base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker),
source_rect, std::move(callback), retry_count + 1));
return;
}
@@ -75,8 +74,8 @@ static void MakeInitialAsyncCopyRequest(
tracker->Add(window);
MakeAsyncCopyRequest(
window->layer(), source_rect,
- base::BindOnce(&FinishedAsyncCopyRequest, base::Passed(&tracker),
- source_rect, std::move(callback), 0));
+ base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker), source_rect,
+ std::move(callback), 0));
}
void GrabWindowSnapshotAndScaleAsyncAura(
diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb
index 1927ae2550e..b8481ee5bc2 100644
--- a/chromium/ui/strings/translations/ui_strings_am.xtb
+++ b/chromium/ui/strings/translations/ui_strings_am.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">ተመለስ</translation>
<translation id="3889424535448813030">ቀኝ ቀስት</translation>
<translation id="3892641579809465218">የውስጥ ማሳያ</translation>
+<translation id="3897092660631435901">ምናሌ</translation>
<translation id="3909791450649380159">&amp;ቁረጥ</translation>
<translation id="3990502903496589789">የቀኝ ጠርዝ</translation>
<translation id="4202807286478387388">ዝለል</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">ይፋ ማሳወቂያ ሦስት ማዕዘን</translation>
<translation id="528468243742722775">ጨርስ</translation>
<translation id="5329858601952122676">&amp;ሠርዝ</translation>
+<translation id="5463830097259460683">ስሜት ገላጭ ምስሎች እና ምልክቶች</translation>
<translation id="5476505524087279545">አታመልክት</translation>
<translation id="5574202486608032840">የ<ph name="IDS_SHORT_PRODUCT_OS_NAME" /> ሥርዓት</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 ደቂቃ ቀርቷል}one{# ደቂቃዎች ቀርቷል}other{# ደቂቃዎች ቀርተዋል}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ቴባ</translation>
+<translation id="7507604095951736240">ስሜት ገላጭ ምስል</translation>
<translation id="7658239707568436148">ይቅር</translation>
<translation id="7781829728241885113">ትናንት</translation>
<translation id="7814458197256864873">&amp;ቅዳ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb
index 228d5cd924a..b3eb8f69c43 100644
--- a/chromium/ui/strings/translations/ui_strings_ar.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ar.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">الرجوع إلى الوراء</translation>
<translation id="3889424535448813030">مفتاح سهم إلى اليمين</translation>
<translation id="3892641579809465218">العرض الداخلي</translation>
+<translation id="3897092660631435901">قائمة</translation>
<translation id="3909791450649380159">&amp;قص</translation>
<translation id="3990502903496589789">الحافة اليسرى</translation>
<translation id="4202807286478387388">الدخول</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">مثلث الإفصاح</translation>
<translation id="528468243742722775">‏مفتاح End</translation>
<translation id="5329858601952122676">&amp;حذف</translation>
+<translation id="5463830097259460683">الرموز التعبيرية والرموز</translation>
<translation id="5476505524087279545">إزالة علامة الاختيار</translation>
<translation id="5574202486608032840">نظام <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{يتبقى دقيقة واحدة}zero{يتبقى # من الدقائق}two{يتبقى دقيقتان (#)}few{يتبقى # دقائق}many{يتبقى # دقيقة}other{يتبقى # من الدقائق}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> تيرابايت</translation>
+<translation id="7507604095951736240">الرموز التعبيرية</translation>
<translation id="7658239707568436148">إلغاء</translation>
<translation id="7781829728241885113">أمس</translation>
<translation id="7814458197256864873">&amp;نسخ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb
index bab7796969d..0aa6e52c4f5 100644
--- a/chromium/ui/strings/translations/ui_strings_bg.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bg.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелка надясно</translation>
<translation id="3892641579809465218">Показване на вътрешна информация</translation>
+<translation id="3897092660631435901">Меню</translation>
<translation id="3909791450649380159">Изрязва&amp;не</translation>
<translation id="3990502903496589789">Десн край</translation>
<translation id="4202807286478387388">преминаване</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Триъгълник за разкриване на съдържание</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Изтриване</translation>
+<translation id="5463830097259460683">Емоджи и символи</translation>
<translation id="5476505524087279545">премахване на отметката</translation>
<translation id="5574202486608032840">Система <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Остава 1 минута}other{Остават # минути}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
+<translation id="7507604095951736240">Емоджи</translation>
<translation id="7658239707568436148">Отказ</translation>
<translation id="7781829728241885113">Вчера</translation>
<translation id="7814458197256864873">&amp;Копиране</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb
index b9f1648d1fe..8475f3e90a7 100644
--- a/chromium/ui/strings/translations/ui_strings_bn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bn.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">ফিরুন</translation>
<translation id="3889424535448813030">Right Arrow</translation>
<translation id="3892641579809465218">অভ্যন্তরীণ প্রদর্শন</translation>
+<translation id="3897092660631435901">মেনু</translation>
<translation id="3909791450649380159">কা&amp;ট করুন</translation>
<translation id="3990502903496589789">ডান প্রান্ত</translation>
<translation id="4202807286478387388">লাফ দিন</translation>
@@ -136,6 +137,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{১ মিনিট বাকি}one{# মিনিট বাকি}other{# মিনিট বাকি}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">ইমোজি</translation>
<translation id="7658239707568436148">বাতিল</translation>
<translation id="7781829728241885113">গতকাল</translation>
<translation id="7814458197256864873">&amp;কপি করুন</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb
index b9815bdaf59..1e2c5d414a2 100644
--- a/chromium/ui/strings/translations/ui_strings_ca.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ca.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Enrere</translation>
<translation id="3889424535448813030">Fletxa dreta</translation>
<translation id="3892641579809465218">Pantalla interna</translation>
+<translation id="3897092660631435901">Menú</translation>
<translation id="3909791450649380159">Re&amp;talla</translation>
<translation id="3990502903496589789">Extrem dret</translation>
<translation id="4202807286478387388">salta</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triangle desplegable</translation>
<translation id="528468243742722775">Fi</translation>
<translation id="5329858601952122676">&amp;Suprimeix</translation>
+<translation id="5463830097259460683">Emojis i símbols</translation>
<translation id="5476505524087279545">desmarca</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Retrocés</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">: <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minut restant}other{# minuts restants}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emojis</translation>
<translation id="7658239707568436148">Cancel·la</translation>
<translation id="7781829728241885113">Ahir</translation>
<translation id="7814458197256864873">&amp;Copia</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb
index b17832346ba..c0c2427efef 100644
--- a/chromium/ui/strings/translations/ui_strings_cs.xtb
+++ b/chromium/ui/strings/translations/ui_strings_cs.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Zpět</translation>
<translation id="3889424535448813030">Klávesa šipka vpravo</translation>
<translation id="3892641579809465218">Interní displej</translation>
+<translation id="3897092660631435901">Nabídka</translation>
<translation id="3909791450649380159">Vyjmou&amp;t</translation>
<translation id="3990502903496589789">Pravý okraj</translation>
<translation id="4202807286478387388">přejít</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Tlačítko k zobrazení skrytého obsahu</translation>
<translation id="528468243742722775">Klávesa End</translation>
<translation id="5329858601952122676">&amp;Smazat</translation>
+<translation id="5463830097259460683">Emodži a symboly</translation>
<translation id="5476505524087279545">odstranit zaškrtnutí</translation>
<translation id="5574202486608032840">Systém <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Zbývá 1 minuta}few{Zbývají # minuty}many{Zbývá # minuty}other{Zbývá # minut}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emodži</translation>
<translation id="7658239707568436148">Zrušit</translation>
<translation id="7781829728241885113">Včera</translation>
<translation id="7814458197256864873">&amp;Kopírovat</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb
index 7f9110a9eb2..fb2aaa73060 100644
--- a/chromium/ui/strings/translations/ui_strings_da.xtb
+++ b/chromium/ui/strings/translations/ui_strings_da.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Tilbage</translation>
<translation id="3889424535448813030">Højrepil</translation>
<translation id="3892641579809465218">Intern skærm</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Kli&amp;p</translation>
<translation id="3990502903496589789">Højre kant</translation>
<translation id="4202807286478387388">hop</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Trekant til at vise eller skjule indhold</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Slet</translation>
+<translation id="5463830097259460683">Emojis og symboler</translation>
<translation id="5476505524087279545">fjern markering</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" />-system</translation>
<translation id="5583640892426849032">Returtast</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minut tilbage}one{# minutter tilbage}other{# minutter tilbage}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Annuller</translation>
<translation id="7781829728241885113">I går</translation>
<translation id="7814458197256864873">&amp;Kopier</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb
index f01349c2950..f10b2bd7787 100644
--- a/chromium/ui/strings/translations/ui_strings_de.xtb
+++ b/chromium/ui/strings/translations/ui_strings_de.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Zurück</translation>
<translation id="3889424535448813030">Rechtspfeil</translation>
<translation id="3892641579809465218">Interne Anzeige</translation>
+<translation id="3897092660631435901">Menü</translation>
<translation id="3909791450649380159">&amp;Ausschneiden</translation>
<translation id="3990502903496589789">Rechter Rand</translation>
<translation id="4202807286478387388">springen</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Aufklappdreieck</translation>
<translation id="528468243742722775">Ende</translation>
<translation id="5329858601952122676">&amp;Löschen</translation>
+<translation id="5463830097259460683">Emojis &amp;&amp; Symbole</translation>
<translation id="5476505524087279545">Auswahl aufheben</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" />-System</translation>
<translation id="5583640892426849032">Rücktaste</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 Minute übrig}other{# Minuten übrig}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emojis</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="7781829728241885113">Gestern</translation>
<translation id="7814458197256864873">&amp;Kopieren</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb
index 1d1f001f571..2b56ba7d0bd 100644
--- a/chromium/ui/strings/translations/ui_strings_el.xtb
+++ b/chromium/ui/strings/translations/ui_strings_el.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Πίσω</translation>
<translation id="3889424535448813030">Δεξιό βέλος</translation>
<translation id="3892641579809465218">Εσωτερική οθόνη</translation>
+<translation id="3897092660631435901">Μενού</translation>
<translation id="3909791450649380159">Απο&amp;κοπή</translation>
<translation id="3990502903496589789">Δεξιά άκρη</translation>
<translation id="4202807286478387388">μεταπήδηση</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Τρίγωνο αποκάλυψης</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Διαγραφή</translation>
+<translation id="5463830097259460683">Emoji και σύμβολα</translation>
<translation id="5476505524087279545">απενεργοποίηση</translation>
<translation id="5574202486608032840">Σύστημα <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Πλήκτρο Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Απομένει 1 λεπτό}other{Απομένουν # λεπτά}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Ακύρωση</translation>
<translation id="7781829728241885113">Χθες</translation>
<translation id="7814458197256864873">&amp;Αντιγραφή</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
index fd7b83c3ada..fe56a9e73c3 100644
--- a/chromium/ui/strings/translations/ui_strings_en-GB.xtb
+++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Back</translation>
<translation id="3889424535448813030">Right Arrow</translation>
<translation id="3892641579809465218">Internal Display</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Cu&amp;t</translation>
<translation id="3990502903496589789">Right Edge</translation>
<translation id="4202807286478387388">jump</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Disclosure triangle</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Delete</translation>
+<translation id="5463830097259460683">Emoji &amp; Symbols</translation>
<translation id="5476505524087279545">untick</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> system</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130"><ph name="MESSAGE" />..</translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minute left}other{# minutes left}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Cancel</translation>
<translation id="7781829728241885113">Yesterday</translation>
<translation id="7814458197256864873">&amp;Copy</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb
index 2d51edc7332..4e9293a1b52 100644
--- a/chromium/ui/strings/translations/ui_strings_es-419.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Atrás</translation>
<translation id="3889424535448813030">Flecha derecha</translation>
<translation id="3892641579809465218">Pantalla interna</translation>
+<translation id="3897092660631435901">Menú</translation>
<translation id="3909791450649380159">Cor&amp;tar</translation>
<translation id="3990502903496589789">Borde derecho</translation>
<translation id="4202807286478387388">saltar</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triángulo desplegable</translation>
<translation id="528468243742722775">Fin</translation>
<translation id="5329858601952122676">&amp;Suprimir</translation>
+<translation id="5463830097259460683">Emoji y símbolos</translation>
<translation id="5476505524087279545">desmarcar</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Tecla de retroceso</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Falta 1 minuto.}other{Faltan # minutos.}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb
index 8d22d321cd7..e98988520e8 100644
--- a/chromium/ui/strings/translations/ui_strings_es.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Atrás</translation>
<translation id="3889424535448813030">Flecha derecha</translation>
<translation id="3892641579809465218">Pantalla interna</translation>
+<translation id="3897092660631435901">Menú</translation>
<translation id="3909791450649380159">Cor&amp;tar</translation>
<translation id="3990502903496589789">Borde derecho</translation>
<translation id="4202807286478387388">saltar</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triángulo de expansión</translation>
<translation id="528468243742722775">Fin</translation>
<translation id="5329858601952122676">&amp;Suprimir</translation>
+<translation id="5463830097259460683">Emojis y símbolos</translation>
<translation id="5476505524087279545">desmarcar</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Tecla de retroceso</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Queda 1 minuto}other{Quedan # minutos}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb
index f2da3fb29a3..b95bb2c95ff 100644
--- a/chromium/ui/strings/translations/ui_strings_et.xtb
+++ b/chromium/ui/strings/translations/ui_strings_et.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Tagasi</translation>
<translation id="3889424535448813030">Paremnool</translation>
<translation id="3892641579809465218">Sisemine kuva</translation>
+<translation id="3897092660631435901">Menüü</translation>
<translation id="3909791450649380159">Lõ&amp;ika</translation>
<translation id="3990502903496589789">Parem serv</translation>
<translation id="4202807286478387388">liigu</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Avalikustamise kolmnurk</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Kustuta</translation>
+<translation id="5463830097259460683">Emotikonid ja sümbolid</translation>
<translation id="5476505524087279545">eemalda mrgistus</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" />-i süsteem</translation>
<translation id="5583640892426849032">Tagasilükkeklahv</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minut on jäänud}other{# minutit on jäänud}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emotikonid</translation>
<translation id="7658239707568436148">Tühista</translation>
<translation id="7781829728241885113">Eile</translation>
<translation id="7814458197256864873">&amp;Kopeeri</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb
index ba3ceda90d6..a1973a57996 100644
--- a/chromium/ui/strings/translations/ui_strings_fa.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fa.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">بازگشت</translation>
<translation id="3889424535448813030">پیکان راست</translation>
<translation id="3892641579809465218">صفحه نمایش داخلی</translation>
+<translation id="3897092660631435901">منو</translation>
<translation id="3909791450649380159">&amp;برش</translation>
<translation id="3990502903496589789">حاشیه راست</translation>
<translation id="4202807286478387388">پرش</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">مثلث افشا</translation>
<translation id="528468243742722775">پایان</translation>
<translation id="5329858601952122676">&amp;حذف</translation>
+<translation id="5463830097259460683">اموجی و نمادها</translation>
<translation id="5476505524087279545">برداشتن علامت</translation>
<translation id="5574202486608032840">سیستم <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{۱ دقیقه باقی مانده است}one{# دقیقه باقی مانده است}other{# دقیقه باقی مانده است}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ترابایت</translation>
+<translation id="7507604095951736240">اموجی</translation>
<translation id="7658239707568436148">لغو</translation>
<translation id="7781829728241885113">دیروز</translation>
<translation id="7814458197256864873">&amp;کپی</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb
index 8a415d066cb..90cbcb38c58 100644
--- a/chromium/ui/strings/translations/ui_strings_fi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fi.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Edellinen</translation>
<translation id="3889424535448813030">Nuoli oik.</translation>
<translation id="3892641579809465218">Sisäinen näyttö</translation>
+<translation id="3897092660631435901">Valikko</translation>
<translation id="3909791450649380159">L&amp;eikkaa</translation>
<translation id="3990502903496589789">Oikea reuna</translation>
<translation id="4202807286478387388">siirry</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Näyttämiskolmio</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Poista</translation>
+<translation id="5463830097259460683">Emojit ja merkit</translation>
<translation id="5476505524087279545">poista valinta</translation>
<translation id="5574202486608032840">Järjestelmä <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Askelpalautin</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minuutti jäljellä}other{# minuuttia jäljellä}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> Tt</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Peruuta</translation>
<translation id="7781829728241885113">Eilen</translation>
<translation id="7814458197256864873">K&amp;opioi</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb
index 6bee96d96f6..b28bc65213d 100644
--- a/chromium/ui/strings/translations/ui_strings_fil.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fil.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Bumalik</translation>
<translation id="3889424535448813030">Right Arrow</translation>
<translation id="3892641579809465218">Panloob na Display</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Al&amp;isin</translation>
<translation id="3990502903496589789">Tamang Lamang</translation>
<translation id="4202807286478387388">tumalon</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Disclosure triangle</translation>
<translation id="528468243742722775">Wakas na</translation>
<translation id="5329858601952122676">&amp;Tanggalin</translation>
+<translation id="5463830097259460683">Emoji at Mga Simbolo</translation>
<translation id="5476505524087279545">i-uncheck</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> system</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minuto na lang ang natitira}one{# minuto na lang ang natitira}other{# na minuto na lang ang natitira}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> (na) TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Ikansela</translation>
<translation id="7781829728241885113">Kahapon</translation>
<translation id="7814458197256864873">&amp;Kopyahin</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb
index 7bc623e0894..0b81cef5b62 100644
--- a/chromium/ui/strings/translations/ui_strings_fr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fr.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Retour</translation>
<translation id="3889424535448813030">Droite</translation>
<translation id="3892641579809465218">Affichage interne</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Cou&amp;per</translation>
<translation id="3990502903496589789">Côté droit</translation>
<translation id="4202807286478387388">accéder</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triangle d'expansion</translation>
<translation id="528468243742722775">Fin</translation>
<translation id="5329858601952122676">&amp;Supprimer</translation>
+<translation id="5463830097259460683">Emoji et symboles</translation>
<translation id="5476505524087279545">décocher</translation>
<translation id="5574202486608032840">Système <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Retour</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minute restante}one{# minute restante}other{# minutes restantes}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> To</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="7781829728241885113">Hier</translation>
<translation id="7814458197256864873">&amp;Copier</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb
index 10b2bc01571..b49d4dac292 100644
--- a/chromium/ui/strings/translations/ui_strings_gu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_gu.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">પાછળ</translation>
<translation id="3889424535448813030">જમણો એરો</translation>
<translation id="3892641579809465218">આંતરિક પ્રદર્શન</translation>
+<translation id="3897092660631435901">મેનૂ</translation>
<translation id="3909791450649380159">કા&amp;પો</translation>
<translation id="3990502903496589789">જમણી કિનારી</translation>
<translation id="4202807286478387388">જંપ કરો</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">પ્રકટીકરણ ત્રિકોણ</translation>
<translation id="528468243742722775">સમાપ્ત</translation>
<translation id="5329858601952122676">&amp;કાઢી નાખો</translation>
+<translation id="5463830097259460683">ઇમોજી અને પ્રતીકો</translation>
<translation id="5476505524087279545">અનચેક કરો</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> સિસ્ટમ</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 મિનિટ બાકી}one{# મિનિટ બાકી}other{# મિનિટ બાકી}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">ઇમોજી</translation>
<translation id="7658239707568436148">રદ કરો</translation>
<translation id="7781829728241885113">ગઈ કાલે</translation>
<translation id="7814458197256864873">&amp;કૉપિ કરો</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb
index aa6556d2906..18129b8ff45 100644
--- a/chromium/ui/strings/translations/ui_strings_hi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hi.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">वापस</translation>
<translation id="3889424535448813030">दायां तीर</translation>
<translation id="3892641579809465218">आंतरिक डिस्प्ले</translation>
+<translation id="3897092660631435901">मेनू</translation>
<translation id="3909791450649380159">&amp;काटें</translation>
<translation id="3990502903496589789">दायां सिरा</translation>
<translation id="4202807286478387388">जाएं</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">प्रकटीकरण त्रिकोण</translation>
<translation id="528468243742722775">समाप्त</translation>
<translation id="5329858601952122676">&amp;हटाएं</translation>
+<translation id="5463830097259460683">इमोजी और चिह्न</translation>
<translation id="5476505524087279545">अनचेक करें</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> सिस्टम</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 मिनट शेष}one{# मिनट शेष}other{# मिनट शेष}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">इमोजी</translation>
<translation id="7658239707568436148">अभी नहीं</translation>
<translation id="7781829728241885113">बीता कल</translation>
<translation id="7814458197256864873">&amp;प्रतिलिपि बनाएं</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb
index 6cf47fc3fa9..750a01f70e6 100644
--- a/chromium/ui/strings/translations/ui_strings_hr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hr.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Natrag</translation>
<translation id="3889424535448813030">Strelica desno</translation>
<translation id="3892641579809465218">Unutarnji zaslon</translation>
+<translation id="3897092660631435901">Izbornik</translation>
<translation id="3909791450649380159">Iz&amp;reži</translation>
<translation id="3990502903496589789">Desni rub</translation>
<translation id="4202807286478387388">skoči</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Trokut za otkrivanje</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Obriši</translation>
+<translation id="5463830097259460683">Emoji i simboli</translation>
<translation id="5476505524087279545">ukloni oznaku</translation>
<translation id="5574202486608032840">Sustav <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Još 1 minuta}one{Još # minuta}few{Još # minute}other{Još # minuta}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Odustani</translation>
<translation id="7781829728241885113">Danas</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb
index 0fdafd9d858..1e80c7233ef 100644
--- a/chromium/ui/strings/translations/ui_strings_hu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hu.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Vissza</translation>
<translation id="3889424535448813030">Jobb nyíl</translation>
<translation id="3892641579809465218">Belső kijelző</translation>
+<translation id="3897092660631435901">Menü</translation>
<translation id="3909791450649380159">Ki&amp;vágás</translation>
<translation id="3990502903496589789">Jobb sarok</translation>
<translation id="4202807286478387388">Mehet</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Plusz tartalom kibontására szolgáló háromszög</translation>
<translation id="528468243742722775">Befejezés</translation>
<translation id="5329858601952122676">&amp;Törlés</translation>
+<translation id="5463830097259460683">Hangulatjelek és szimbólumok</translation>
<translation id="5476505524087279545">Megjelölés eltávolítása</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> rendszer</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 perc van hátra}other{# perc van hátra}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Hangulatjel</translation>
<translation id="7658239707568436148">Mégse</translation>
<translation id="7781829728241885113">Tegnap</translation>
<translation id="7814458197256864873">&amp;Másolás</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb
index e1c9196b510..18ffa8fd29a 100644
--- a/chromium/ui/strings/translations/ui_strings_id.xtb
+++ b/chromium/ui/strings/translations/ui_strings_id.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Mundur</translation>
<translation id="3889424535448813030">Panah Kanan</translation>
<translation id="3892641579809465218">Tampilan Internal</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Po&amp;tong</translation>
<translation id="3990502903496589789">Tepi Kanan</translation>
<translation id="4202807286478387388">lompati</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Segitiga aksesibilitas</translation>
<translation id="528468243742722775">Berakhir</translation>
<translation id="5329858601952122676">&amp;Hapus</translation>
+<translation id="5463830097259460683">Emoji &amp;&amp; Simbol</translation>
<translation id="5476505524087279545">batalkan centang</translation>
<translation id="5574202486608032840">Sistem <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130"><ph name="MESSAGE" /> -</translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 menit lagi}other{# menit lagi}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Kemarin</translation>
<translation id="7814458197256864873">&amp;Salin</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb
index 332b8572fe1..bc8a1fa0687 100644
--- a/chromium/ui/strings/translations/ui_strings_it.xtb
+++ b/chromium/ui/strings/translations/ui_strings_it.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Indietro</translation>
<translation id="3889424535448813030">Freccia destra</translation>
<translation id="3892641579809465218">Display interno</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">T&amp;aglia</translation>
<translation id="3990502903496589789">Margine destro</translation>
<translation id="4202807286478387388">vai</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triangolo di apertura</translation>
<translation id="528468243742722775">Fine</translation>
<translation id="5329858601952122676">&amp;Elimina</translation>
+<translation id="5463830097259460683">Emoji e simboli</translation>
<translation id="5476505524087279545">deseleziona</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minuto rimanente}other{# minuti rimanenti}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Annulla</translation>
<translation id="7781829728241885113">Ieri</translation>
<translation id="7814458197256864873">&amp;Copia</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb
index 3bb12bb04df..2f8680de334 100644
--- a/chromium/ui/strings/translations/ui_strings_iw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_iw.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">חזור</translation>
<translation id="3889424535448813030">חץ לימין</translation>
<translation id="3892641579809465218">תצוגה פנימית</translation>
+<translation id="3897092660631435901">תפריט</translation>
<translation id="3909791450649380159">גז&amp;ור</translation>
<translation id="3990502903496589789">קצה ימני</translation>
<translation id="4202807286478387388">קפוץ</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">משולש הצגה</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;מחק</translation>
+<translation id="5463830097259460683">אמוג'י וסמלים</translation>
<translation id="5476505524087279545">בטל סימון</translation>
<translation id="5574202486608032840">מערכת <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{נותרה דקה אחת}two{נותרו # דקות}many{נותרו # דקות}other{נותרו # דקות}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">אמוג'י</translation>
<translation id="7658239707568436148">ביטול</translation>
<translation id="7781829728241885113">אתמול</translation>
<translation id="7814458197256864873">&amp;העתק</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb
index ff073ffb2b4..5bfe1b27291 100644
--- a/chromium/ui/strings/translations/ui_strings_ja.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ja.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">戻る</translation>
<translation id="3889424535448813030">右矢印キー</translation>
<translation id="3892641579809465218">内蔵ディスプレイ</translation>
+<translation id="3897092660631435901">メニュー</translation>
<translation id="3909791450649380159">切り取り(&amp;T)</translation>
<translation id="3990502903496589789">右端</translation>
<translation id="4202807286478387388">ジャンプ</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">三角形の展開ボタン</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">削除(&amp;D)</translation>
+<translation id="5463830097259460683">絵文字と記号</translation>
<translation id="5476505524087279545">チェックを外す</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> システム</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{残り 1 分}other{残り # 分}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">絵文字</translation>
<translation id="7658239707568436148">キャンセル</translation>
<translation id="7781829728241885113">昨日</translation>
<translation id="7814458197256864873">コピー(&amp;C)</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb
index 28bd579f118..41c4bf81481 100644
--- a/chromium/ui/strings/translations/ui_strings_kn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_kn.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">ಹಿಂದೆ</translation>
<translation id="3889424535448813030">ಬಲ ಬಾಣದ ಗುರುತು</translation>
<translation id="3892641579809465218">ಆಂತರಿಕ ಪ್ರದರ್ಶನ</translation>
+<translation id="3897092660631435901">ಮೆನು</translation>
<translation id="3909791450649380159">ಕತ್ತರಿ&amp;ಸು</translation>
<translation id="3990502903496589789">ಬಲ ತುದಿ</translation>
<translation id="4202807286478387388">ಹಾರು</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">ತ್ರಿಕೋನ ಪ್ರಕಟಣೆ</translation>
<translation id="528468243742722775">ಅಂತ್ಯ</translation>
<translation id="5329858601952122676">&amp;ಅಳಿಸು</translation>
+<translation id="5463830097259460683">ಎಮೋಜಿ ಮತ್ತು ಸಂಕೇತಗಳು</translation>
<translation id="5476505524087279545">ಪರೀಕ್ಷಿಸಬೇಡಿ</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> ಸಿಸ್ಟಂ</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130"><ph name="MESSAGE" /> -</translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 ನಿಮಿಷ ಉಳಿದಿದೆ}one{# ನಿಮಿಷಗಳು ಉಳಿದಿವೆ}other{# ನಿಮಿಷಗಳು ಉಳಿದಿವೆ}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">ಎಮೋಜಿ</translation>
<translation id="7658239707568436148">ರದ್ದುಮಾಡಿ</translation>
<translation id="7781829728241885113">ನಿನ್ನೆ</translation>
<translation id="7814458197256864873">&amp;ನಕಲಿಸಿ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb
index b0e7af9a5a5..c2c66637c69 100644
--- a/chromium/ui/strings/translations/ui_strings_ko.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ko.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">뒤로</translation>
<translation id="3889424535448813030">오른쪽 화살표</translation>
<translation id="3892641579809465218">내부 디스플레이</translation>
+<translation id="3897092660631435901">메뉴</translation>
<translation id="3909791450649380159">잘라내기(&amp;T)</translation>
<translation id="3990502903496589789">오른쪽 모서리</translation>
<translation id="4202807286478387388">건너뛰기</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">펼치기/접기 삼각형</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">삭제(&amp;D)</translation>
+<translation id="5463830097259460683">그림 이모티콘 &amp;&amp; 기호</translation>
<translation id="5476505524087279545">선택 해제</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> 시스템</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1분 남음}other{#분 남음}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" />TB</translation>
+<translation id="7507604095951736240">그림 이모티콘</translation>
<translation id="7658239707568436148">취소</translation>
<translation id="7781829728241885113">어제</translation>
<translation id="7814458197256864873">복사(&amp;C)</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb
index fe75e98d64e..c7f1db3cf26 100644
--- a/chromium/ui/strings/translations/ui_strings_lt.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lt.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Grįžti</translation>
<translation id="3889424535448813030">Rodyklė į dešinę</translation>
<translation id="3892641579809465218">Vidinė pateiktis</translation>
+<translation id="3897092660631435901">Meniu</translation>
<translation id="3909791450649380159">Iškir&amp;pti</translation>
<translation id="3990502903496589789">Dešinysis kraštas</translation>
<translation id="4202807286478387388">peršokti</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Paskelbimo trikampis</translation>
<translation id="528468243742722775">Pabaiga</translation>
<translation id="5329858601952122676">&amp;Pašalinti</translation>
+<translation id="5463830097259460683">Jaustukai ir simboliai</translation>
<translation id="5476505524087279545">Nuimti žymėjimą</translation>
<translation id="5574202486608032840">„<ph name="IDS_SHORT_PRODUCT_OS_NAME" />“ sistema</translation>
<translation id="5583640892426849032">Grįžties klavišas</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Liko 1 minutė}one{Liko # minutė}few{Liko # minutės}many{Liko # minutės}other{Liko # minučių}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Jaustukai</translation>
<translation id="7658239707568436148">Atšaukti</translation>
<translation id="7781829728241885113">Vakar</translation>
<translation id="7814458197256864873">&amp;Kopijuoti</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb
index 66b620dbcc7..5159a73d256 100644
--- a/chromium/ui/strings/translations/ui_strings_lv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lv.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Atpakaļ</translation>
<translation id="3889424535448813030">Labā bulta</translation>
<translation id="3892641579809465218">Iekšējais displejs</translation>
+<translation id="3897092660631435901">Izvēlne</translation>
<translation id="3909791450649380159">Izgrie&amp;zt</translation>
<translation id="3990502903496589789">Labā puse</translation>
<translation id="4202807286478387388">lekt</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Atklāšanas trijstūris</translation>
<translation id="528468243742722775">Beigas</translation>
<translation id="5329858601952122676">Dzēst</translation>
+<translation id="5463830097259460683">Emocijzīmes un simboli</translation>
<translation id="5476505524087279545">neprbaudt</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> sistēma</translation>
<translation id="5583640892426849032">Atkāpšanās taustiņš</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Atlikusi 1 minūte}zero{Atlikušas # minūtes}one{Atlikusi # minūte}other{Atlikušas # minūtes}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emocijzīmes</translation>
<translation id="7658239707568436148">Atcelt</translation>
<translation id="7781829728241885113">Vakar</translation>
<translation id="7814458197256864873">Ko&amp;pēt</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb
index e70bb0a838f..bdc85332e76 100644
--- a/chromium/ui/strings/translations/ui_strings_ml.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ml.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">പിന്നോട്ട്</translation>
<translation id="3889424535448813030">വലതുഭാഗത്തെ അമ്പടയാളം</translation>
<translation id="3892641579809465218">ആന്തരിക പ്രദർശനം</translation>
+<translation id="3897092660631435901">മെനു</translation>
<translation id="3909791450649380159">&amp;മുറിക്കുക</translation>
<translation id="3990502903496589789">വലത് അഗ്രം</translation>
<translation id="4202807286478387388">jump</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">ഡിസ്‌ക്ലോഷർ ത്രികോണം</translation>
<translation id="528468243742722775">അവസാനം</translation>
<translation id="5329858601952122676">&amp;ഇല്ലാതാക്കൂ</translation>
+<translation id="5463830097259460683">ഇമോജിയും ചിഹ്നങ്ങളും</translation>
<translation id="5476505524087279545">അണ്‍ചെക്ക് ചെയ്യുക</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> സിസ്‌റ്റം</translation>
<translation id="5583640892426849032">ബാക്ക്‌സ്പെയ്‌സ്</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{ഒരു മിനിറ്റ് ശേഷിക്കുന്നു}other{# മിനിറ്റ് ശേഷിക്കുന്നു}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">ഇമോജി</translation>
<translation id="7658239707568436148">റദ്ദാക്കൂ</translation>
<translation id="7781829728241885113">ഇന്നലെ</translation>
<translation id="7814458197256864873">&amp;പകര്‍ത്തൂ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb
index 7ae05d047ca..88b069f7341 100644
--- a/chromium/ui/strings/translations/ui_strings_mr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mr.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">मागील</translation>
<translation id="3889424535448813030">Right Arrow</translation>
<translation id="3892641579809465218">अंतर्गत डिस्प्ले</translation>
+<translation id="3897092660631435901">मेनू</translation>
<translation id="3909791450649380159">क&amp;ट करा</translation>
<translation id="3990502903496589789">उजवा काठ</translation>
<translation id="4202807286478387388">जंप करा</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">प्रकटन त्रिकोण</translation>
<translation id="528468243742722775">समाप्त</translation>
<translation id="5329858601952122676">&amp;हटवा</translation>
+<translation id="5463830097259460683">इमोजी &amp;&amp; चिन्हे</translation>
<translation id="5476505524087279545">अनचेक</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> सिस्टम</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 मिनिट शिल्लक}one{# मिनिट शिल्लक}other{# मिनिटे शिल्लक}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">इमोजी</translation>
<translation id="7658239707568436148">रद्द करा</translation>
<translation id="7781829728241885113">काल</translation>
<translation id="7814458197256864873">&amp;कॉपी करा</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb
index de467150e5a..fadd4aa7bca 100644
--- a/chromium/ui/strings/translations/ui_strings_ms.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ms.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Kembali</translation>
<translation id="3889424535448813030">Anak Panah Kanan</translation>
<translation id="3892641579809465218">Paparan Dalaman</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Po&amp;tong</translation>
<translation id="3990502903496589789">Tepi Kanan</translation>
<translation id="4202807286478387388">lompat</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Segi tiga pendedahan</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Padam</translation>
+<translation id="5463830097259460683">Emoji &amp;&amp; Simbol</translation>
<translation id="5476505524087279545">nyahpilih</translation>
<translation id="5574202486608032840">Sistem <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Undur ruang</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minit lagi}other{# minit lagi}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Semalam</translation>
<translation id="7814458197256864873">&amp;Salin</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb
index 8d248d1be85..4b9446d6aa6 100644
--- a/chromium/ui/strings/translations/ui_strings_nl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_nl.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Vorige</translation>
<translation id="3889424535448813030">Pijl-rechts</translation>
<translation id="3892641579809465218">Interne display</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">&amp;Knippen</translation>
<translation id="3990502903496589789">Rechterzijde</translation>
<translation id="4202807286478387388">Gaan naar</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Driehoek voor samen-/uitvouwen</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">Verwij&amp;deren</translation>
+<translation id="5463830097259460683">Emoji en symbolen</translation>
<translation id="5476505524087279545">Deselecteren</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" />-systeem</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minuut resterend}other{# minuten resterend}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji's</translation>
<translation id="7658239707568436148">Annuleren</translation>
<translation id="7781829728241885113">Gisteren</translation>
<translation id="7814458197256864873">&amp;Kopiëren</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb
index 75a5e61eab4..e067e8cb72e 100644
--- a/chromium/ui/strings/translations/ui_strings_no.xtb
+++ b/chromium/ui/strings/translations/ui_strings_no.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Tilbake</translation>
<translation id="3889424535448813030">Pil høyre</translation>
<translation id="3892641579809465218">Innebygd skjerm</translation>
+<translation id="3897092660631435901">Meny</translation>
<translation id="3909791450649380159">Klipp u&amp;t</translation>
<translation id="3990502903496589789">Høyre kant</translation>
<translation id="4202807286478387388">hopp</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Trekant for mer innhold</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Slett</translation>
+<translation id="5463830097259460683">Emoji og symboler</translation>
<translation id="5476505524087279545">fjern merke</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" />-systemet</translation>
<translation id="5583640892426849032">Tilbake-tasten</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minutt igjen}other{# minutter igjen}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">I går</translation>
<translation id="7814458197256864873">&amp;Kopier</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb
index 122dabf9eaa..1e13afa5ff4 100644
--- a/chromium/ui/strings/translations/ui_strings_pl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pl.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Wstecz</translation>
<translation id="3889424535448813030">Strzałka w prawo</translation>
<translation id="3892641579809465218">Wyświetlacz wewnętrzny</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Wy&amp;tnij</translation>
<translation id="3990502903496589789">Krawędź po prawej</translation>
<translation id="4202807286478387388">przejdź</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Trójkąt rozwinięcia</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Usuń</translation>
+<translation id="5463830097259460683">Emotikony i symbole</translation>
<translation id="5476505524087279545">odznacz</translation>
<translation id="5574202486608032840">System <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Pozostała 1 minuta}few{Pozostały # minuty}many{Pozostały # minut}other{Pozostało # minuty}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emotikony</translation>
<translation id="7658239707568436148">Anuluj</translation>
<translation id="7781829728241885113">Wczoraj</translation>
<translation id="7814458197256864873">&amp;Kopiuj</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
index b6921f06ef2..81faabeb213 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Voltar</translation>
<translation id="3889424535448813030">Seta para a direita</translation>
<translation id="3892641579809465218">Display interno</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">&amp;Recortar</translation>
<translation id="3990502903496589789">Borda direita</translation>
<translation id="4202807286478387388">pular</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triângulo de divulgação</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Excluir</translation>
+<translation id="5463830097259460683">Emoticons e símbolos</translation>
<translation id="5476505524087279545">desmarcar</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Um minuto restante}one{# minutos restantes}other{# minutos restantes}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoticons</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
<translation id="7814458197256864873">Co&amp;piar</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
index 161d2155cf8..99163a69641 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Anterior</translation>
<translation id="3889424535448813030">Seta para a direita</translation>
<translation id="3892641579809465218">Ecrã interno</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Cor&amp;tar</translation>
<translation id="3990502903496589789">Margem direita</translation>
<translation id="4202807286478387388">ir para</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triângulo de divulgação</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">E&amp;liminar</translation>
+<translation id="5463830097259460683">Emoji e símbolos</translation>
<translation id="5476505524087279545">desmarcar</translation>
<translation id="5574202486608032840">Sistema <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Retrocesso</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Falta 1 minuto}other{Faltam # minutos}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb
index 15f275f6fef..4c10c480920 100644
--- a/chromium/ui/strings/translations/ui_strings_ro.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ro.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Înapoi</translation>
<translation id="3889424535448813030">Săgeată spre dreapta</translation>
<translation id="3892641579809465218">Afișaj intern</translation>
+<translation id="3897092660631435901">Meniu</translation>
<translation id="3909791450649380159">&amp;Taie</translation>
<translation id="3990502903496589789">Marginea dreaptă</translation>
<translation id="4202807286478387388">accesează</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Triunghi pentru afișare</translation>
<translation id="528468243742722775">Sfârșit</translation>
<translation id="5329858601952122676">&amp;Șterge</translation>
+<translation id="5463830097259460683">Emoji și simboluri</translation>
<translation id="5476505524087279545">debifează</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Un minut rămas}few{# minute rămase}other{# de minute rămase}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Anulează</translation>
<translation id="7781829728241885113">Ieri</translation>
<translation id="7814458197256864873">&amp;Copiază</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
index b15eefc26da..f68c6f150ac 100644
--- a/chromium/ui/strings/translations/ui_strings_ru.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелка вправо</translation>
<translation id="3892641579809465218">Встроенный дисплей</translation>
+<translation id="3897092660631435901">Меню</translation>
<translation id="3909791450649380159">Выре&amp;зать</translation>
<translation id="3990502903496589789">Правый край</translation>
<translation id="4202807286478387388">перейти</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Треугольник развертывания</translation>
<translation id="528468243742722775">Завершить</translation>
<translation id="5329858601952122676">&amp;Удалить</translation>
+<translation id="5463830097259460683">Эмодзи и символы</translation>
<translation id="5476505524087279545">снять галочку</translation>
<translation id="5574202486608032840">Система <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Клавиша возврата (Backspace)</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Осталась 1 минута}one{Осталась # минута}few{Осталось # минуты}many{Осталось # минут}other{Осталось # минуты}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
+<translation id="7507604095951736240">Эмодзи</translation>
<translation id="7658239707568436148">Отмена</translation>
<translation id="7781829728241885113">Вчера</translation>
<translation id="7814458197256864873">&amp;Копировать</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb
index 52a378f444e..f483bff60a9 100644
--- a/chromium/ui/strings/translations/ui_strings_sk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sk.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Naspäť</translation>
<translation id="3889424535448813030">Šípka doprava</translation>
<translation id="3892641579809465218">Interný displej</translation>
+<translation id="3897092660631435901">Ponuka</translation>
<translation id="3909791450649380159">&amp;Vystrihnúť</translation>
<translation id="3990502903496589789">Pravý okraj</translation>
<translation id="4202807286478387388">skok</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Trojuholníkové tlačidlo na zobrazenie skrytého obsahu</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Odstrániť</translation>
+<translation id="5463830097259460683">Emodži a symboly</translation>
<translation id="5476505524087279545">zrušiť označenie</translation>
<translation id="5574202486608032840">Systém <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Zostáva 1 minúta}few{Zostávajú # minúty}many{Zostáva # minúty}other{Zostáva # minút}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emodži</translation>
<translation id="7658239707568436148">Zrušiť</translation>
<translation id="7781829728241885113">Včera</translation>
<translation id="7814458197256864873">&amp;Kopírovať</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb
index 9b23c7aee33..01f3b4e90f8 100644
--- a/chromium/ui/strings/translations/ui_strings_sl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sl.xtb
@@ -59,6 +59,7 @@
<translation id="385051799172605136">Nazaj</translation>
<translation id="3889424535448813030">Puščica desno</translation>
<translation id="3892641579809465218">Notranji zaslon</translation>
+<translation id="3897092660631435901">Meni</translation>
<translation id="3909791450649380159">Izrež&amp;i</translation>
<translation id="3990502903496589789">Desni rob</translation>
<translation id="4202807286478387388">skoči</translation>
@@ -80,6 +81,7 @@
<translation id="520299402983819650"><ph name="QUANTITY" /> PB</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Izbriši</translation>
+<translation id="5463830097259460683">Emodži in drugi znaki</translation>
<translation id="5476505524087279545">počisti izbor</translation>
<translation id="5583640892426849032">Vračalka</translation>
<translation id="5613020302032141669">Puščica levo</translation>
@@ -129,6 +131,7 @@
<translation id="7365057348334984696">{MINUTES,plural, =1{Pred 1 min}one{Pred # min}two{Pred # min}few{Pred # min}other{Pred # min}}</translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Še 1 min}one{Še # min}two{Še # min}few{Še # min}other{Še # min}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Prekliči</translation>
<translation id="7781829728241885113">Včeraj</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb
index bee93c7b1a1..9a0ac7ef98f 100644
--- a/chromium/ui/strings/translations/ui_strings_sr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sr.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелица надесно</translation>
<translation id="3892641579809465218">Интерни екран</translation>
+<translation id="3897092660631435901">Мени</translation>
<translation id="3909791450649380159">Ис&amp;еци</translation>
<translation id="3990502903496589789">Десна ивица</translation>
<translation id="4202807286478387388">прескочи</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Троугао за откривање</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Избриши</translation>
+<translation id="5463830097259460683">Емоџи и симболи</translation>
<translation id="5476505524087279545">опозови избор</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> систем</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Још 1 минут}one{Још # минут}few{Још # минута}other{Још # минута}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Емоџи</translation>
<translation id="7658239707568436148">Откажи</translation>
<translation id="7781829728241885113">Јуче</translation>
<translation id="7814458197256864873">&amp;Копирај</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb
index 2dcdbb2375c..1a78da15e1f 100644
--- a/chromium/ui/strings/translations/ui_strings_sv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sv.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Bakåt</translation>
<translation id="3889424535448813030">Högerpil</translation>
<translation id="3892641579809465218">Intern bildskärm</translation>
+<translation id="3897092660631435901">Meny</translation>
<translation id="3909791450649380159">&amp;Klipp ut</translation>
<translation id="3990502903496589789">Högerkant</translation>
<translation id="4202807286478387388">fortsätta</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Utökningstriangel</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Ta bort</translation>
+<translation id="5463830097259460683">Emoji och symboler</translation>
<translation id="5476505524087279545">kryssa av</translation>
<translation id="5574202486608032840">Operativsystemet <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backsteg</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 minut kvar}other{# minuter kvar}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">Igår</translation>
<translation id="7814458197256864873">&amp;Kopiera</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb
index 5cfc38c89f7..d1ee5087c70 100644
--- a/chromium/ui/strings/translations/ui_strings_sw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sw.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Nyuma</translation>
<translation id="3889424535448813030">Mshale Kulia</translation>
<translation id="3892641579809465218">Onyesho la Ndani</translation>
+<translation id="3897092660631435901">Menyu</translation>
<translation id="3909791450649380159">&amp;Kata</translation>
<translation id="3990502903496589789">Ncha ya Kulia</translation>
<translation id="4202807286478387388">ruka</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Pembe tatu ya ufumbuzi</translation>
<translation id="528468243742722775">Mwisho</translation>
<translation id="5329858601952122676">&amp;Futa</translation>
+<translation id="5463830097259460683">Emoji na Ishara</translation>
<translation id="5476505524087279545">toa tiki</translation>
<translation id="5574202486608032840">Mfumo wa <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Imesalia dakika 1}other{Zimesalia dakika #}}</translation>
<translation id="7460907917090416791">TB <ph name="QUANTITY" /></translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">Ghairi</translation>
<translation id="7781829728241885113">Jana</translation>
<translation id="7814458197256864873">&amp;Nakili</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb
index 66df98a941f..b85acb0aa92 100644
--- a/chromium/ui/strings/translations/ui_strings_ta.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ta.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">முந்தைய பக்கம்</translation>
<translation id="3889424535448813030">வலது அம்பு</translation>
<translation id="3892641579809465218">இணையக் காட்சி</translation>
+<translation id="3897092660631435901">மெனு</translation>
<translation id="3909791450649380159">வெட்&amp;டு</translation>
<translation id="3990502903496589789">வலது விளிம்பு</translation>
<translation id="4202807286478387388">தாவு</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">கூடுதல் உள்ளடக்கத்தைக் காட்டும் முக்கோணம்</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;நீக்கு</translation>
+<translation id="5463830097259460683">ஈமோஜி &amp;&amp; குறியீடுகள்</translation>
<translation id="5476505524087279545">தேர்வு நீக்கு</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> சாதனம்</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 நிமிடம் மீதமுள்ளது}other{# நிமிடங்கள் மீதமுள்ளன}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> டெ.பை</translation>
+<translation id="7507604095951736240">ஈமோஜி</translation>
<translation id="7658239707568436148">ரத்து செய்</translation>
<translation id="7781829728241885113">நேற்று</translation>
<translation id="7814458197256864873">&amp;நகலெடு</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb
index 4e84a0122b2..948f7a18530 100644
--- a/chromium/ui/strings/translations/ui_strings_te.xtb
+++ b/chromium/ui/strings/translations/ui_strings_te.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">వెనుకకు</translation>
<translation id="3889424535448813030">కుడి బాణం</translation>
<translation id="3892641579809465218">అంతర్గత ప్రదర్శన</translation>
+<translation id="3897092660631435901">మెను</translation>
<translation id="3909791450649380159">క&amp;త్తిరించు</translation>
<translation id="3990502903496589789">కుడి సరిహద్దు</translation>
<translation id="4202807286478387388">వెళ్ళు</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">కంటెంట్‌ను విస్తరింపజేసే లేదా కుదించే త్రిభుజం</translation>
<translation id="528468243742722775">ముగింపు</translation>
<translation id="5329858601952122676">&amp;తొలగించు</translation>
+<translation id="5463830097259460683">ఎమోజి &amp;&amp; చిహ్నాలు</translation>
<translation id="5476505524087279545">ఎంపిక చెయ్యబడలేదు</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> సిస్టమ్</translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 నిమిషం మిగిలి ఉంది}other{# నిమిషాలు మిగిలి ఉన్నాయి}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">ఎమోజి</translation>
<translation id="7658239707568436148">రద్దు చెయ్యి</translation>
<translation id="7781829728241885113">నిన్న</translation>
<translation id="7814458197256864873">&amp;కాపీ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb
index 7aa7da8ca72..1a7d9b66377 100644
--- a/chromium/ui/strings/translations/ui_strings_th.xtb
+++ b/chromium/ui/strings/translations/ui_strings_th.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">กลับ</translation>
<translation id="3889424535448813030">ลูกศรขวา</translation>
<translation id="3892641579809465218">จอแสดงผลภายใน</translation>
+<translation id="3897092660631435901">เมนู</translation>
<translation id="3909791450649380159">&amp;ตัด</translation>
<translation id="3990502903496589789">ขอบขวา</translation>
<translation id="4202807286478387388">ข้าม</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">สามเหลี่ยมซ่อนเนื้อหา</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;ลบ</translation>
+<translation id="5463830097259460683">อีโมจิและสัญลักษณ์</translation>
<translation id="5476505524087279545">ยกเลิกการทำเครื่องหมาย</translation>
<translation id="5574202486608032840">ระบบ <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{เหลือ 1 นาที}other{เหลือ # นาที}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">อีโมจิ</translation>
<translation id="7658239707568436148">ยกเลิก</translation>
<translation id="7781829728241885113">เมื่อวานนี้</translation>
<translation id="7814458197256864873">&amp;คัดลอก</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb
index ff48f705d6d..7bea7f3ff6a 100644
--- a/chromium/ui/strings/translations/ui_strings_tr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_tr.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Geri</translation>
<translation id="3889424535448813030">Sağ Ok</translation>
<translation id="3892641579809465218">Dahili Ekran</translation>
+<translation id="3897092660631435901">Menü</translation>
<translation id="3909791450649380159">&amp;Kes</translation>
<translation id="3990502903496589789">Sağ Kenar</translation>
<translation id="4202807286478387388">git</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Açıklama üçgeni</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Sil</translation>
+<translation id="5463830097259460683">Emoji ve Semboller</translation>
<translation id="5476505524087279545">işareti kaldır</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> sistemi</translation>
<translation id="5583640892426849032">Geri al tuşu</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{1 dakika kaldı}other{# dakika kaldı}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Emoji</translation>
<translation id="7658239707568436148">İptal</translation>
<translation id="7781829728241885113">Dün</translation>
<translation id="7814458197256864873">K&amp;opyala</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb
index e470d44a019..a20aa1e013f 100644
--- a/chromium/ui/strings/translations/ui_strings_uk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_uk.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Курсор праворуч</translation>
<translation id="3892641579809465218">Внутрішній екран</translation>
+<translation id="3897092660631435901">Меню</translation>
<translation id="3909791450649380159">Вирізат&amp;и</translation>
<translation id="3990502903496589789">Правий край</translation>
<translation id="4202807286478387388">перейти</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Трикутник відкривання</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Видалити</translation>
+<translation id="5463830097259460683">Смайли та символи</translation>
<translation id="5476505524087279545">зняти прапорець</translation>
<translation id="5574202486608032840">Система <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">– <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Залишилась 1 хвилина}one{Залишилася # хвилина}few{Залишилося # хвилини}many{Залишилося # хвилин}other{Залишилося # хвилини}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
+<translation id="7507604095951736240">Смайли</translation>
<translation id="7658239707568436148">Скасувати</translation>
<translation id="7781829728241885113">Учора</translation>
<translation id="7814458197256864873">&amp;Копіювати</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb
index 0278c309ae6..706148b670e 100644
--- a/chromium/ui/strings/translations/ui_strings_vi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_vi.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">Quay lại</translation>
<translation id="3889424535448813030">Mũi tên phải</translation>
<translation id="3892641579809465218">Màn hình nội bộ</translation>
+<translation id="3897092660631435901">Menu</translation>
<translation id="3909791450649380159">Cắ&amp;t</translation>
<translation id="3990502903496589789">Cạnh bên Phải</translation>
<translation id="4202807286478387388">chuyển</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">Tam giác hiển thị</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;Xoá</translation>
+<translation id="5463830097259460683">Các ký hiệu &amp;&amp; biểu tượng cảm xúc</translation>
<translation id="5476505524087279545">bỏ chọn</translation>
<translation id="5574202486608032840">Hệ thống <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{Còn 1 phút}other{Còn # phút}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">Biểu tượng cảm xúc</translation>
<translation id="7658239707568436148">Hủy</translation>
<translation id="7781829728241885113">Hôm qua</translation>
<translation id="7814458197256864873">Sao &amp;chép</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
index 1dc0dbb27d5..29b5610e58c 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">后退</translation>
<translation id="3889424535448813030">向右箭头</translation>
<translation id="3892641579809465218">内部显示屏</translation>
+<translation id="3897092660631435901">菜单</translation>
<translation id="3909791450649380159">剪切(&amp;T)</translation>
<translation id="3990502903496589789">右边缘</translation>
<translation id="4202807286478387388">略过</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">开合三角标记</translation>
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">删除(&amp;D)</translation>
+<translation id="5463830097259460683">表情符号与符号</translation>
<translation id="5476505524087279545">取消选中</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /> 系统</translation>
<translation id="5583640892426849032">退格</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{还剩 1 分钟}other{还剩 # 分钟}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">表情符号</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7781829728241885113">昨天</translation>
<translation id="7814458197256864873">复制(&amp;C)</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
index ad478c47f7b..a6b1941a96c 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
@@ -63,6 +63,7 @@
<translation id="385051799172605136">返回</translation>
<translation id="3889424535448813030">向右鍵</translation>
<translation id="3892641579809465218">內建顯示器</translation>
+<translation id="3897092660631435901">選單</translation>
<translation id="3909791450649380159">剪下(&amp;T)</translation>
<translation id="3990502903496589789">右邊緣</translation>
<translation id="4202807286478387388">跳至另一頁</translation>
@@ -85,6 +86,7 @@
<translation id="5266161281976477809">顯示/隱藏三角標記</translation>
<translation id="528468243742722775">結束</translation>
<translation id="5329858601952122676">刪除(&amp;D)</translation>
+<translation id="5463830097259460683">表情符號和符號</translation>
<translation id="5476505524087279545">取消選取</translation>
<translation id="5574202486608032840"><ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace 鍵</translation>
@@ -136,6 +138,7 @@
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{還剩 1 分鐘}other{還剩 # 分鐘}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
+<translation id="7507604095951736240">表情符號</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7781829728241885113">昨天</translation>
<translation id="7814458197256864873">複製(&amp;C)</translation>
diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd
index 3e0b41a4055..29ebbdcf7ce 100644
--- a/chromium/ui/strings/ui_strings.grd
+++ b/chromium/ui/strings/ui_strings.grd
@@ -435,6 +435,9 @@ need to be translated for each locale.-->
<message name="IDS_APP_ACCNAME_RESTORE" desc="The accessible name for the Restore button.">
Restore
</message>
+ <message name="IDS_APP_ACCNAME_MENU" desc="The accessible name for the Menu button.">
+ Menu
+ </message>
<!-- Scroll Bar Context Menu Labels -->
<message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE" desc="The label for the 'Scroll Here' item">
@@ -497,6 +500,16 @@ need to be translated for each locale.-->
Select &amp;All
</message>
</if>
+ <if expr="not is_macosx">
+ <message name="IDS_CONTENT_CONTEXT_EMOJI" desc="The context menu item to display the OS-provided emoji picker.">
+ Emoji
+ </message>
+ </if>
+ <if expr="is_macosx">
+ <message name="IDS_CONTENT_CONTEXT_EMOJI" desc="The context menu item to display the OS-provided emoji picker.">
+ Emoji &amp;&amp; Symbols
+ </message>
+ </if>
<!-- Generic terms -->
<message name="IDS_APP_OK" desc="Used for Ok on buttons">
diff --git a/chromium/ui/touch_selection/touch_handle.cc b/chromium/ui/touch_selection/touch_handle.cc
index 65b1dba8e82..503f9eab771 100644
--- a/chromium/ui/touch_selection/touch_handle.cc
+++ b/chromium/ui/touch_selection/touch_handle.cc
@@ -330,6 +330,10 @@ void TouchHandle::UpdateHandleLayout() {
drawable_->SetOrigin(ComputeHandleOrigin());
}
+void TouchHandle::SetTransparent() {
+ SetAlpha(0.f);
+}
+
gfx::PointF TouchHandle::ComputeHandleOrigin() const {
gfx::PointF focus = mirror_vertical_ ? focus_top_ : focus_bottom_;
gfx::RectF drawable_bounds = drawable_->GetVisibleBounds();
diff --git a/chromium/ui/touch_selection/touch_handle.h b/chromium/ui/touch_selection/touch_handle.h
index 3815fea5237..3952593001c 100644
--- a/chromium/ui/touch_selection/touch_handle.h
+++ b/chromium/ui/touch_selection/touch_handle.h
@@ -120,6 +120,10 @@ class UI_TOUCH_SELECTION_EXPORT TouchHandle : public TouchSelectionDraggable {
// for the same frame update due to more than one parameter updates.
void UpdateHandleLayout();
+ // Set the handle to transparent. Handle will be set to opaque again in
+ // EndDrag() call.
+ void SetTransparent();
+
const gfx::PointF& focus_bottom() const { return focus_bottom_; }
TouchHandleOrientation orientation() const { return orientation_; }
float alpha() const { return alpha_; }
diff --git a/chromium/ui/touch_selection/touch_handle_unittest.cc b/chromium/ui/touch_selection/touch_handle_unittest.cc
index c723009d0f3..991f44b975d 100644
--- a/chromium/ui/touch_selection/touch_handle_unittest.cc
+++ b/chromium/ui/touch_selection/touch_handle_unittest.cc
@@ -4,7 +4,6 @@
#include "ui/touch_selection/touch_handle.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/test/motion_event_test_utils.h"
#include "ui/gfx/geometry/rect_f.h"
diff --git a/chromium/ui/touch_selection/touch_selection_controller.cc b/chromium/ui/touch_selection/touch_selection_controller.cc
index 8ea5e0b5cac..49b991ec968 100644
--- a/chromium/ui/touch_selection/touch_selection_controller.cc
+++ b/chromium/ui/touch_selection/touch_selection_controller.cc
@@ -46,7 +46,8 @@ TouchSelectionController::Config::Config()
: max_tap_duration(base::TimeDelta::FromMilliseconds(300)),
tap_slop(8),
enable_adaptive_handle_orientation(false),
- enable_longpress_drag_selection(false) {}
+ enable_longpress_drag_selection(false),
+ hide_active_handle(false) {}
TouchSelectionController::Config::~Config() {
}
@@ -341,6 +342,8 @@ void TouchSelectionController::OnDragBegin(
const gfx::PointF& drag_position) {
if (&draggable == insertion_handle_.get()) {
DCHECK_EQ(active_status_, INSERTION_ACTIVE);
+ if (config_.hide_active_handle)
+ insertion_handle_->SetTransparent();
client_->OnSelectionEvent(INSERTION_HANDLE_DRAG_STARTED);
anchor_drag_to_selection_start_ = true;
return;
@@ -359,6 +362,14 @@ void TouchSelectionController::OnDragBegin(
(drag_position - GetEndPosition()).LengthSquared();
}
+ if (config_.hide_active_handle) {
+ if (&draggable == start_selection_handle_.get()) {
+ start_selection_handle_->SetTransparent();
+ } else if (&draggable == end_selection_handle_.get()) {
+ end_selection_handle_->SetTransparent();
+ }
+ }
+
gfx::PointF base = GetStartPosition() + GetStartLineOffset();
gfx::PointF extent = GetEndPosition() + GetEndLineOffset();
if (anchor_drag_to_selection_start_)
diff --git a/chromium/ui/touch_selection/touch_selection_controller.h b/chromium/ui/touch_selection/touch_selection_controller.h
index 2214024f7ef..24c1a8e5250 100644
--- a/chromium/ui/touch_selection/touch_selection_controller.h
+++ b/chromium/ui/touch_selection/touch_selection_controller.h
@@ -66,6 +66,9 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController
// Controls whether drag selection after a longpress is enabled.
// Defaults to false.
bool enable_longpress_drag_selection;
+
+ // Should we hide the active handle.
+ bool hide_active_handle;
};
TouchSelectionController(TouchSelectionControllerClient* client,
diff --git a/chromium/ui/touch_selection/touch_selection_controller_test_api.cc b/chromium/ui/touch_selection/touch_selection_controller_test_api.cc
index fe5a14306f1..5132672b2a0 100644
--- a/chromium/ui/touch_selection/touch_selection_controller_test_api.cc
+++ b/chromium/ui/touch_selection/touch_selection_controller_test_api.cc
@@ -34,6 +34,13 @@ float TouchSelectionControllerTestApi::GetEndAlpha() const {
return 0.f;
}
+float TouchSelectionControllerTestApi::GetInsertionHandleAlpha() const {
+ if (controller_->active_status_ == TouchSelectionController::INSERTION_ACTIVE)
+ return controller_->insertion_handle_->alpha();
+
+ return 0.f;
+}
+
TouchHandleOrientation
TouchSelectionControllerTestApi::GetStartHandleOrientation() const {
if (controller_->active_status_ != TouchSelectionController::SELECTION_ACTIVE)
diff --git a/chromium/ui/touch_selection/touch_selection_controller_test_api.h b/chromium/ui/touch_selection/touch_selection_controller_test_api.h
index 6454b9e8999..c9cb0c7551a 100644
--- a/chromium/ui/touch_selection/touch_selection_controller_test_api.h
+++ b/chromium/ui/touch_selection/touch_selection_controller_test_api.h
@@ -22,6 +22,7 @@ class TouchSelectionControllerTestApi {
bool GetEndVisible() const;
float GetStartAlpha() const;
float GetEndAlpha() const;
+ float GetInsertionHandleAlpha() const;
TouchHandleOrientation GetStartHandleOrientation() const;
TouchHandleOrientation GetEndHandleOrientation() const;
diff --git a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
index d0bf65b32bc..84331436c7e 100644
--- a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
+++ b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -7,7 +7,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/test/motion_event_test_utils.h"
@@ -118,6 +117,12 @@ class TouchSelectionControllerTest : public testing::Test,
controller_.reset(new TouchSelectionController(this, config));
}
+ void SetHideActiveHandle(bool hide) {
+ TouchSelectionController::Config config = DefaultConfig();
+ config.hide_active_handle = hide;
+ controller_.reset(new TouchSelectionController(this, config));
+ }
+
void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
@@ -1457,4 +1462,148 @@ TEST_F(TouchSelectionControllerTest, SelectionUpdateDragPosition) {
EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
}
+TEST_F(TouchSelectionControllerTest, NoHideActiveInsertionHandle) {
+ SetHideActiveHandle(false);
+ TouchSelectionControllerTestApi test_controller(&controller());
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ float line_height = 10.f;
+ gfx::RectF insertion_rect(10, 0, 0, line_height);
+ bool visible = true;
+ OnTapEvent();
+
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
+
+ SetDraggingEnabled(true);
+ EXPECT_EQ(1.f, test_controller.GetInsertionHandleAlpha());
+ MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetInsertionHandleAlpha());
+}
+
+TEST_F(TouchSelectionControllerTest, HideActiveInsertionHandle) {
+ SetHideActiveHandle(true);
+ TouchSelectionControllerTestApi test_controller(&controller());
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ float line_height = 10.f;
+ gfx::RectF insertion_rect(10, 0, 0, line_height);
+ bool visible = true;
+ OnTapEvent();
+
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
+
+ SetDraggingEnabled(true);
+ EXPECT_EQ(1.f, test_controller.GetInsertionHandleAlpha());
+ MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(0.f, test_controller.GetInsertionHandleAlpha());
+
+ event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(0.f, test_controller.GetInsertionHandleAlpha());
+
+ event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs);
+ // UP will reset the alpha to visible.
+ event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetInsertionHandleAlpha());
+}
+
+TEST_F(TouchSelectionControllerTest, NoHideActiveSelectionHandle) {
+ SetHideActiveHandle(false);
+ TouchSelectionControllerTestApi test_controller(&controller());
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ float line_height = 10.f;
+ gfx::RectF start_rect(10, 0, 0, line_height);
+ gfx::RectF end_rect(50, 0, 0, line_height);
+ bool visible = true;
+ OnLongPressEvent();
+
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Start handle.
+ SetDraggingEnabled(true);
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+ MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ // End handle.
+ event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 50, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs);
+ event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 50, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+}
+
+TEST_F(TouchSelectionControllerTest, HideActiveSelectionHandle) {
+ SetHideActiveHandle(true);
+ TouchSelectionControllerTestApi test_controller(&controller());
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ float line_height = 10.f;
+ gfx::RectF start_rect(10, 0, 0, line_height);
+ gfx::RectF end_rect(50, 0, 0, line_height);
+ bool visible = true;
+ OnLongPressEvent();
+
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Start handle.
+ SetDraggingEnabled(true);
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+ MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(0.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(0.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs);
+ // UP will reset alpha to be visible.
+ event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+
+ // End handle.
+ event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 50, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(0.f, test_controller.GetEndAlpha());
+
+ event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 50, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(0.f, test_controller.GetEndAlpha());
+
+ event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs);
+ // UP will reset alpha to be visible.
+ event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 50, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(1.f, test_controller.GetStartAlpha());
+ EXPECT_EQ(1.f, test_controller.GetEndAlpha());
+}
+
} // namespace ui
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index 8d72c2a2b31..32f534f12e3 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -22,14 +22,24 @@ aggregate_vector_icons("views_vector_icons") {
icons = [
"checkbox_active.icon",
"checkbox_normal.icon",
- "menu_check.1x.icon",
+ "close.icon",
+ "ic_close.icon",
+ "info.icon",
+ "launch.icon",
"menu_check.icon",
"menu_radio_empty.icon",
"menu_radio_selected.icon",
+ "new_incognito_window.icon",
+ "new_tab.icon",
+ "new_window.icon",
+ "open.icon",
+ "options.icon",
+ "pin.icon",
"radio_button_active.icon",
"radio_button_normal.icon",
- "submenu_arrow.1x.icon",
"submenu_arrow.icon",
+ "uninstall.icon",
+ "unpin.icon",
]
}
@@ -110,6 +120,7 @@ jumbo_component("views") {
"controls/label.h",
"controls/link.h",
"controls/link_listener.h",
+ "controls/menu/menu_closure_animation_mac.h",
"controls/menu/menu_config.h",
"controls/menu/menu_controller.h",
"controls/menu/menu_controller_delegate.h",
@@ -307,6 +318,7 @@ jumbo_component("views") {
"controls/label.cc",
"controls/link.cc",
"controls/menu/display_change_listener_mac.cc",
+ "controls/menu/menu_closure_animation_mac.mm",
"controls/menu/menu_config.cc",
"controls/menu/menu_config_chromeos.cc",
"controls/menu/menu_config_linux.cc",
@@ -626,6 +638,7 @@ jumbo_component("views") {
deps += [
"//services/ui/public/interfaces",
"//ui/aura",
+ "//ui/platform_window",
"//ui/touch_selection",
"//ui/wm",
"//ui/wm/public",
@@ -685,6 +698,11 @@ jumbo_component("views") {
}
}
+ if (is_linux) {
+ sources += [ "widget/desktop_aura/desktop_window_tree_host_platform.cc" ]
+ public += [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ]
+ }
+
if (is_mac) {
sources -= [ "controls/views_text_services_context_menu.cc" ]
deps += [
@@ -783,6 +801,8 @@ jumbo_source_set("test_support_internal") {
"test/views_test_helper_mac.mm",
"test/widget_test.cc",
"test/widget_test.h",
+ "test/widget_test_api.cc",
+ "test/widget_test_api.h",
"test/widget_test_mac.mm",
"test/x11_property_change_waiter.cc",
"test/x11_property_change_waiter.h",
@@ -803,7 +823,7 @@ jumbo_source_set("test_support_internal") {
"//base/test:test_support",
"//gpu/ipc/service",
"//ipc:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/base",
@@ -915,6 +935,7 @@ source_set("views_unittests_sources") {
"cocoa/drag_drop_client_mac_unittest.mm",
"controls/button/blue_button_unittest.cc",
"controls/button/button_unittest.cc",
+ "controls/button/checkbox_unittest.cc",
"controls/button/image_button_factory_unittest.cc",
"controls/button/image_button_unittest.cc",
"controls/button/label_button_label_unittest.cc",
@@ -1117,7 +1138,7 @@ test("views_unittests") {
deps = [
":views_unittests_sources",
- "//mojo/edk/system",
+ "//mojo/edk",
]
}
@@ -1135,7 +1156,7 @@ source_set("views_interactive_ui_tests") {
":views",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/base:test_support",
@@ -1194,13 +1215,13 @@ test("views_perftests") {
":test_support",
"//base/test:test_support",
"//cc/base:base",
- "//mojo/edk/system",
+ "//mojo/edk",
"//testing/perf",
"//ui/resources:ui_test_pak",
]
data_deps = [
"//ui/resources:ui_test_pak_data",
- "//testing:run_gtest_perf_test",
+ "//testing:run_perf_test",
]
}
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index 41eaa521433..e6f8d868ebf 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -16,6 +16,7 @@ include_rules = [
"+ui/gl/test/gl_surface_test_support.h", # To initialize GL for tests.
"+ui/native_theme",
"+ui/ozone/public",
+ "+ui/platform_window",
"+ui/resources/grit/ui_resources.h",
"+ui/strings/grit/ui_strings.h",
"+ui/touch_selection",
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index 68aaca376d8..5a5ca2dd36c 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -151,4 +151,11 @@ void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window,
}
}
+void AXWindowObjWrapper::OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) {
+ AXAuraObjCache::GetInstance()->FireEvent(
+ AXAuraObjCache::GetInstance()->GetOrCreate(window_),
+ ax::mojom::Event::kStateChanged);
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
index a1f5834f5d3..9904dc471d7 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -48,6 +48,7 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override;
+ void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
private:
aura::Window* window_;
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
index 0be9b7cfd75..1d155c6fa74 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/stl_util.h"
#include "ui/accessibility/ax_action_data.h"
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_base.cc b/chromium/ui/views/accessibility/native_view_accessibility_base.cc
index 9997f88dd95..e895c9d3418 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_base.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_base.cc
@@ -7,7 +7,8 @@
#include "ui/views/accessibility/native_view_accessibility_base.h"
-#include "base/memory/ptr_util.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/native_widget_types.h"
@@ -22,6 +23,17 @@ namespace {
base::LazyInstance<std::map<int32_t, ui::AXPlatformNode*>>::Leaky
g_unique_id_to_ax_platform_node = LAZY_INSTANCE_INITIALIZER;
+// Information required to fire a delayed accessibility event.
+struct QueuedEvent {
+ ax::mojom::Event type;
+ int32_t node_id;
+};
+
+base::LazyInstance<std::vector<QueuedEvent>>::Leaky g_event_queue =
+ LAZY_INSTANCE_INITIALIZER;
+
+bool g_is_queueing_events = false;
+
bool IsAccessibilityFocusableWhenEnabled(View* view) {
return view->focus_behavior() != View::FocusBehavior::NEVER &&
view->IsDrawn();
@@ -59,8 +71,36 @@ ui::AXPlatformNode* FromNativeWindow(gfx::NativeWindow native_window) {
return ui::AXPlatformNode::FromNativeViewAccessible(native_view_accessible);
}
+ui::AXPlatformNode* PlatformNodeFromNodeID(int32_t id) {
+ // Note: For Views, node IDs and unique IDs are the same - but that isn't
+ // necessarily true for all AXPlatformNodes.
+ auto it = g_unique_id_to_ax_platform_node.Get().find(id);
+
+ if (it == g_unique_id_to_ax_platform_node.Get().end())
+ return nullptr;
+
+ return it->second;
+}
+
+void FireEvent(QueuedEvent event) {
+ ui::AXPlatformNode* node = PlatformNodeFromNodeID(event.node_id);
+ if (node)
+ node->NotifyAccessibilityEvent(event.type);
+}
+
+void FlushQueue() {
+ DCHECK(g_is_queueing_events);
+ for (QueuedEvent event : g_event_queue.Get())
+ FireEvent(event);
+ g_is_queueing_events = false;
+ g_event_queue.Get().clear();
+}
+
} // namespace
+// static
+int32_t NativeViewAccessibilityBase::fake_focus_view_id_ = 0;
+
NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view)
: ViewAccessibility(view) {
ax_node_ = ui::AXPlatformNode::Create(this);
@@ -87,7 +127,22 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::GetNativeObject() {
void NativeViewAccessibilityBase::NotifyAccessibilityEvent(
ax::mojom::Event event_type) {
+ if (g_is_queueing_events) {
+ g_event_queue.Get().push_back({event_type, GetUniqueId().Get()});
+ return;
+ }
+
ax_node_->NotifyAccessibilityEvent(event_type);
+
+ // A focus context event is intended to send a focus event and a delay
+ // before the next focus event. It makes sense to delay the entire next
+ // synchronous batch of next events so that ordering remains the same.
+ if (event_type == ax::mojom::Event::kFocusContext) {
+ // Begin queueing subsequent events and flush queue asynchronously.
+ g_is_queueing_events = true;
+ base::OnceCallback<void()> cb = base::BindOnce(&FlushQueue);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(cb));
+ }
}
// ui::AXPlatformNodeDelegate
@@ -226,22 +281,36 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::HitTestSync(int x,
return GetNativeObject();
}
+void NativeViewAccessibilityBase::OnAutofillShown() {
+ // When the autofill is shown, treat it and the currently selected item as
+ // focused, even though the actual focus is in the browser's currently
+ // focused textfield.
+ DCHECK(!fake_focus_view_id_) << "Cannot have more that one fake focus.";
+ fake_focus_view_id_ = GetUniqueId().Get();
+ ui::AXPlatformNode::OnAutofillShown();
+}
+
+void NativeViewAccessibilityBase::OnAutofillHidden() {
+ DCHECK(fake_focus_view_id_ == GetUniqueId().Get())
+ << "Cannot clear fake focus on an object that did not have fake focus.";
+ fake_focus_view_id_ = 0;
+ ui::AXPlatformNode::OnAutofillHidden();
+}
+
gfx::NativeViewAccessible NativeViewAccessibilityBase::GetFocus() {
FocusManager* focus_manager = view()->GetFocusManager();
View* focused_view =
focus_manager ? focus_manager->GetFocusedView() : nullptr;
+ if (fake_focus_view_id_) {
+ ui::AXPlatformNode* ax_node = PlatformNodeFromNodeID(fake_focus_view_id_);
+ if (ax_node)
+ return ax_node->GetNativeViewAccessible();
+ }
return focused_view ? focused_view->GetNativeViewAccessible() : nullptr;
}
ui::AXPlatformNode* NativeViewAccessibilityBase::GetFromNodeID(int32_t id) {
- // Note: For Views, node IDs and unique IDs are the same - but that isn't
- // necessarily true for all AXPlatformNodes.
- auto it = g_unique_id_to_ax_platform_node.Get().find(id);
-
- if (it == g_unique_id_to_ax_platform_node.Get().end())
- return nullptr;
-
- return it->second;
+ return PlatformNodeFromNodeID(id);
}
int NativeViewAccessibilityBase::GetIndexInParent() const {
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_base.h b/chromium/ui/views/accessibility/native_view_accessibility_base.h
index 18fe003a7fc..cb3d15a8eec 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_base.h
+++ b/chromium/ui/views/accessibility/native_view_accessibility_base.h
@@ -37,6 +37,8 @@ class VIEWS_EXPORT NativeViewAccessibilityBase
// ViewAccessibility:
gfx::NativeViewAccessible GetNativeObject() override;
void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
+ void OnAutofillShown() override;
+ void OnAutofillHidden() override;
// ui::AXPlatformNodeDelegate
const ui::AXNodeData& GetData() const override;
@@ -74,6 +76,11 @@ class VIEWS_EXPORT NativeViewAccessibilityBase
mutable ui::AXNodeData data_;
+ // This allows UI popups like autofill to act as if they are focused in the
+ // exposed platform accessibility API, even though true focus remains in
+ // underlying content.
+ static int32_t fake_focus_view_id_;
+
DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityBase);
};
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_mac.mm b/chromium/ui/views/accessibility/native_view_accessibility_mac.mm
index c6374ceaaa7..be5b1978fde 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_mac.mm
+++ b/chromium/ui/views/accessibility/native_view_accessibility_mac.mm
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
index d146b33705f..c4904034e0c 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/geometry/rect_conversions.h"
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win.cc b/chromium/ui/views/accessibility/native_view_accessibility_win.cc
index bc1ef854510..7491a60f6f0 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_win.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_win.cc
@@ -10,7 +10,6 @@
#include <set>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
@@ -25,7 +24,6 @@
#include "ui/base/win/atl_module.h"
#include "ui/display/win/screen_win.h"
#include "ui/views/controls/button/button.h"
-#include "ui/views/focus/focus_manager.h"
#include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h"
#include "ui/wm/core/window_util.h"
diff --git a/chromium/ui/views/accessibility/view_accessibility.cc b/chromium/ui/views/accessibility/view_accessibility.cc
index 133b4d4368d..91a0db6df8a 100644
--- a/chromium/ui/views/accessibility/view_accessibility.cc
+++ b/chromium/ui/views/accessibility/view_accessibility.cc
@@ -97,7 +97,7 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
if (!owner_view_->enabled())
data->SetRestriction(ax::mojom::Restriction::kDisabled);
- if (!owner_view_->visible())
+ if (!owner_view_->visible() && data->role != ax::mojom::Role::kAlert)
data->AddState(ax::mojom::State::kInvisible);
if (owner_view_->context_menu_controller())
diff --git a/chromium/ui/views/accessibility/view_accessibility.h b/chromium/ui/views/accessibility/view_accessibility.h
index 8dc947bd63a..6a366b4cb6f 100644
--- a/chromium/ui/views/accessibility/view_accessibility.h
+++ b/chromium/ui/views/accessibility/view_accessibility.h
@@ -51,6 +51,9 @@ class VIEWS_EXPORT ViewAccessibility {
void OverrideDescription(const std::string& description);
void OverrideIsLeaf(); // Force this node to be treated as a leaf node.
+ virtual void OnAutofillShown(){};
+ virtual void OnAutofillHidden(){};
+
virtual gfx::NativeViewAccessible GetNativeObject();
virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) {}
diff --git a/chromium/ui/views/accessible_pane_view.cc b/chromium/ui/views/accessible_pane_view.cc
index a22b6967a34..87cb386a30c 100644
--- a/chromium/ui/views/accessible_pane_view.cc
+++ b/chromium/ui/views/accessible_pane_view.cc
@@ -4,7 +4,6 @@
#include "ui/views/accessible_pane_view.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/views/focus/focus_search.h"
diff --git a/chromium/ui/views/animation/ink_drop.h b/chromium/ui/views/animation/ink_drop.h
index 3569e01f261..00de74cc3e3 100644
--- a/chromium/ui/views/animation/ink_drop.h
+++ b/chromium/ui/views/animation/ink_drop.h
@@ -36,6 +36,14 @@ class VIEWS_EXPORT InkDrop {
// Animates from the current InkDropState to |ink_drop_state|.
virtual void AnimateToState(InkDropState ink_drop_state) = 0;
+ // Sets hover highlight fade animations to last for |duration_ms|
+ // milliseconds.
+ virtual void SetHoverHighlightFadeDurationMs(int duration_ms) = 0;
+
+ // Clears any set hover highlight fade durations and uses the default
+ // durations instead.
+ virtual void UseDefaultHoverHighlightFadeDuration() = 0;
+
// Immediately snaps the InkDropState to ACTIVATED and HIDDEN specifically.
// These are more specific implementations of the non-existent
// SnapToState(InkDropState) function are the only ones available because they
diff --git a/chromium/ui/views/animation/ink_drop_highlight_unittest.cc b/chromium/ui/views/animation/ink_drop_highlight_unittest.cc
index f804b934b5a..22f43856bcc 100644
--- a/chromium/ui/views/animation/ink_drop_highlight_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_highlight_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer.h"
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index 5a769f05902..8a60f37c9fb 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -4,7 +4,6 @@
#include "ui/views/animation/ink_drop_host_view.h"
-#include "base/memory/ptr_util.h"
#include "ui/events/event.h"
#include "ui/events/scoped_target_handler.h"
#include "ui/gfx/color_palette.h"
@@ -168,6 +167,10 @@ std::unique_ptr<InkDropHighlight> InkDropHostView::CreateInkDropHighlight()
gfx::RectF(GetMirroredRect(GetContentsBounds())).CenterPoint());
}
+std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const {
+ return nullptr;
+}
+
std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple(
const gfx::Point& center_point,
const gfx::Size& size) const {
@@ -278,10 +281,6 @@ SkColor InkDropHostView::GetInkDropBaseColor() const {
return gfx::kPlaceholderColor;
}
-std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const {
- return nullptr;
-}
-
bool InkDropHostView::HasInkDrop() const {
return !!ink_drop_;
}
@@ -298,12 +297,9 @@ InkDrop* InkDropHostView::GetInkDrop() {
}
void InkDropHostView::InstallInkDropMask(ui::Layer* ink_drop_layer) {
-// Layer masks don't work on Windows. See crbug.com/713359
-#if !defined(OS_WIN)
ink_drop_mask_ = CreateInkDropMask();
if (ink_drop_mask_)
ink_drop_layer->SetMaskLayer(ink_drop_mask_->layer());
-#endif
}
void InkDropHostView::ResetInkDropMask() {
@@ -316,13 +312,9 @@ void InkDropHostView::UpdateInkDropMaskLayerSize(const gfx::Size& new_size) {
}
std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
- std::unique_ptr<InkDropImpl> ink_drop =
- std::make_unique<InkDropImpl>(this, size());
- views::InkDropImpl::AutoHighlightMode mode =
- PlatformStyle::kUseRipples
- ? views::InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE
- : views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE;
- ink_drop->SetAutoHighlightMode(mode);
+ auto ink_drop = std::make_unique<InkDropImpl>(this, size());
+ ink_drop->SetAutoHighlightMode(
+ InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE);
return ink_drop;
}
diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h
index 34ea050d06a..81d018254a5 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.h
+++ b/chromium/ui/views/animation/ink_drop_host_view.h
@@ -45,6 +45,12 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override;
+ // Subclasses can override to return a mask for the ink drop. By default,
+ // returns nullptr (i.e no mask).
+ // TODO(bruthig): InkDropMasks do not currently work on Windows. See
+ // https://crbug.com/713359.
+ virtual std::unique_ptr<views::InkDropMask> CreateInkDropMask() const;
+
// Toggle to enable/disable an InkDrop on this View. Descendants can override
// CreateInkDropHighlight() and CreateInkDropRipple() to change the look/feel
// of the InkDrop.
@@ -107,12 +113,6 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
// ink drop.
virtual SkColor GetInkDropBaseColor() const;
- // Subclasses can override to return a mask for the ink drop. By default,
- // returns nullptr (i.e no mask).
- // TODO(bruthig): InkDropMasks do not currently work on Windows. See
- // crbug.com/713359.
- virtual std::unique_ptr<views::InkDropMask> CreateInkDropMask() const;
-
// Called after a new InkDrop instance is created.
virtual void OnInkDropCreated() {}
diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc
index f052e387114..96328205c27 100644
--- a/chromium/ui/views/animation/ink_drop_impl.cc
+++ b/chromium/ui/views/animation/ink_drop_impl.cc
@@ -5,12 +5,12 @@
#include "ui/views/animation/ink_drop_impl.h"
#include "base/auto_reset.h"
-#include "base/memory/ptr_util.h"
#include "base/timer/timer.h"
#include "ui/compositor/layer.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_host.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
+#include "ui/views/style/platform_style.h"
namespace views {
@@ -170,11 +170,15 @@ void InkDropImpl::NoAutoHighlightHiddenState::Enter() {
}
void InkDropImpl::NoAutoHighlightHiddenState::ShowOnHoverChanged() {
- HandleHoverAndFocusChangeChanges(kHighlightFadeInOnHoverChangeDurationMs);
+ HandleHoverAndFocusChangeChanges(
+ GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+ kHighlightFadeInOnHoverChangeDurationMs));
}
void InkDropImpl::NoAutoHighlightHiddenState::OnHoverChanged() {
- HandleHoverAndFocusChangeChanges(kHighlightFadeInOnHoverChangeDurationMs);
+ HandleHoverAndFocusChangeChanges(
+ GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+ kHighlightFadeInOnHoverChangeDurationMs));
}
void InkDropImpl::NoAutoHighlightHiddenState::ShowOnFocusChanged() {
@@ -215,11 +219,15 @@ void InkDropImpl::NoAutoHighlightVisibleState::Enter() {
}
void InkDropImpl::NoAutoHighlightVisibleState::ShowOnHoverChanged() {
- HandleHoverAndFocusChangeChanges(kHighlightFadeOutOnHoverChangeDurationMs);
+ HandleHoverAndFocusChangeChanges(
+ GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+ kHighlightFadeOutOnHoverChangeDurationMs));
}
void InkDropImpl::NoAutoHighlightVisibleState::OnHoverChanged() {
- HandleHoverAndFocusChangeChanges(kHighlightFadeOutOnHoverChangeDurationMs);
+ HandleHoverAndFocusChangeChanges(
+ GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+ kHighlightFadeOutOnHoverChangeDurationMs));
}
void InkDropImpl::NoAutoHighlightVisibleState::ShowOnFocusChanged() {
@@ -612,6 +620,12 @@ void InkDropImpl::SetAutoHighlightMode(AutoHighlightMode auto_highlight_mode) {
SetHighlightState(highlight_state_factory_->CreateStartState());
}
+void InkDropImpl::SetAutoHighlightModeForPlatform() {
+ SetAutoHighlightMode(PlatformStyle::kUseRipples
+ ? AutoHighlightMode::HIDE_ON_RIPPLE
+ : AutoHighlightMode::SHOW_ON_RIPPLE);
+}
+
void InkDropImpl::HostSizeChanged(const gfx::Size& new_size) {
// |root_layer_| should fill the entire host because it affects the clipping
// when a mask layer is applied to it. This will not affect clipping if no
@@ -640,6 +654,14 @@ void InkDropImpl::AnimateToState(InkDropState ink_drop_state) {
ink_drop_ripple_->AnimateToState(ink_drop_state);
}
+void InkDropImpl::SetHoverHighlightFadeDurationMs(int duration_ms) {
+ hover_highlight_fade_duration_ms_ = duration_ms;
+}
+
+void InkDropImpl::UseDefaultHoverHighlightFadeDuration() {
+ hover_highlight_fade_duration_ms_.reset();
+}
+
void InkDropImpl::SnapToActivated() {
DestroyHiddenTargetedAnimations();
if (!ink_drop_ripple_)
diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h
index 98ec237e3f7..05862e299d8 100644
--- a/chromium/ui/views/animation/ink_drop_impl.h
+++ b/chromium/ui/views/animation/ink_drop_impl.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/animation/ink_drop.h"
@@ -61,10 +62,21 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// InkDrop inherited functions.
void SetAutoHighlightMode(AutoHighlightMode auto_highlight_mode);
+ // Sets the AutoHighlightMode as per the platform. Platforms that show ripples
+ // will be set to HIDE_ON_RIPPLE, and platforms that don't show ripples are
+ // set to SHOW_ON_RIPPLE highlight behavior.
+ void SetAutoHighlightModeForPlatform();
+
+ const base::Optional<int>& hover_highlight_fade_duration_ms() const {
+ return hover_highlight_fade_duration_ms_;
+ }
+
// InkDrop:
void HostSizeChanged(const gfx::Size& new_size) override;
InkDropState GetTargetInkDropState() const override;
void AnimateToState(InkDropState ink_drop_state) override;
+ void SetHoverHighlightFadeDurationMs(int duration_ms) override;
+ void UseDefaultHoverHighlightFadeDuration() override;
void SnapToActivated() override;
void SnapToHidden() override;
void SetHovered(bool is_hovered) override;
@@ -301,6 +313,9 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// of the |highlight_|.
std::unique_ptr<HighlightState> highlight_state_;
+ // Overrides the default hover highlight fade durations when set.
+ base::Optional<int> hover_highlight_fade_duration_ms_;
+
// Used to ensure highlight state transitions are not triggered when exiting
// the current state.
bool exiting_highlight_state_;
diff --git a/chromium/ui/views/animation/ink_drop_impl_unittest.cc b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
index 02ad6f75265..e485be3aba9 100644
--- a/chromium/ui/views/animation/ink_drop_impl_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
@@ -7,7 +7,6 @@
#include "ui/views/animation/ink_drop_impl.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/test/gtest_util.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/ui/views/animation/ink_drop_stub.cc b/chromium/ui/views/animation/ink_drop_stub.cc
index 9a8237b3c11..5cc5d006971 100644
--- a/chromium/ui/views/animation/ink_drop_stub.cc
+++ b/chromium/ui/views/animation/ink_drop_stub.cc
@@ -18,6 +18,10 @@ InkDropState InkDropStub::GetTargetInkDropState() const {
void InkDropStub::AnimateToState(InkDropState state) {}
+void InkDropStub::SetHoverHighlightFadeDurationMs(int duration_ms) {}
+
+void InkDropStub::UseDefaultHoverHighlightFadeDuration() {}
+
void InkDropStub::SnapToActivated() {}
void InkDropStub::SnapToHidden() {}
diff --git a/chromium/ui/views/animation/ink_drop_stub.h b/chromium/ui/views/animation/ink_drop_stub.h
index 86ed8829824..a1b441a1bc8 100644
--- a/chromium/ui/views/animation/ink_drop_stub.h
+++ b/chromium/ui/views/animation/ink_drop_stub.h
@@ -22,6 +22,8 @@ class VIEWS_EXPORT InkDropStub : public InkDrop {
void HostSizeChanged(const gfx::Size& new_size) override;
InkDropState GetTargetInkDropState() const override;
void AnimateToState(InkDropState state) override;
+ void SetHoverHighlightFadeDurationMs(int duration_ms) override;
+ void UseDefaultHoverHighlightFadeDuration() override;
void SnapToActivated() override;
void SnapToHidden() override;
void SetHovered(bool is_hovered) override;
diff --git a/chromium/ui/views/background.cc b/chromium/ui/views/background.cc
index 93bd98fcf87..3b728d72dc7 100644
--- a/chromium/ui/views/background.cc
+++ b/chromium/ui/views/background.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/scoped_observer.h"
#include "build/build_config.h"
#include "ui/gfx/canvas.h"
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index e2292a8f620..44e7b93fddc 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -62,13 +62,12 @@ BorderImages::~BorderImages() {}
namespace {
+// The border corner radius for material design bubble borders.
+constexpr int kMaterialDesignCornerRadius = 2;
+
// The border is stroked at 1px, but for the purposes of reserving space we have
// to deal in dip coordinates, so round up to 1dip.
-const int kBorderThicknessDip = 1;
-
-bool UseMaterialDesign() {
- return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
+constexpr int kBorderThicknessDip = 1;
// Utility functions for getting alignment points on the edge of a rectangle.
gfx::Point CenterTop(const gfx::Rect& rect) {
@@ -177,25 +176,30 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
background_color_(color),
use_theme_background_color_(false) {
DCHECK(shadow_ < SHADOW_COUNT);
- if (UseMaterialDesign()) {
- // Harmony bubbles don't use arrows.
- alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
- arrow_paint_type_ = PAINT_NONE;
- } else {
- images_ = GetBorderImages(shadow_);
- }
+ Init();
}
BubbleBorder::~BubbleBorder() {}
// static
-gfx::Insets BubbleBorder::GetBorderAndShadowInsets() {
+gfx::Insets BubbleBorder::GetBorderAndShadowInsets(
+ base::Optional<int> elevation) {
+ if (elevation.has_value()) {
+ return -gfx::ShadowValue::GetMargin(GetShadowValues(elevation)) +
+ gfx::Insets(kBorderThicknessDip);
+ }
+
constexpr gfx::Insets blur(kShadowBlur + kBorderThicknessDip);
constexpr gfx::Insets offset(-kShadowVerticalOffset, 0, kShadowVerticalOffset,
0);
return blur + offset;
}
+void BubbleBorder::SetCornerRadius(int corner_radius) {
+ corner_radius_ = corner_radius;
+ Init();
+}
+
void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
if (UseMaterialDesign())
return;
@@ -208,7 +212,8 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
// TODO(estade): handle more anchor positions.
if (UseMaterialDesign() &&
(arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
- arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER)) {
+ arrow_ == TOP_CENTER || arrow_ == LEFT_CENTER ||
+ arrow_ == RIGHT_CENTER)) {
gfx::Rect contents_bounds(contents_size);
// Apply the border part of the inset before calculating coordinates because
// the border should align with the anchor's border. For the purposes of
@@ -228,6 +233,8 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
anchor_rect.bottom_left() - contents_bounds.origin();
} else if (arrow_ == BOTTOM_CENTER) {
contents_bounds += CenterTop(anchor_rect) - CenterBottom(contents_bounds);
+ } else if (arrow_ == TOP_CENTER) {
+ contents_bounds += CenterBottom(anchor_rect) - CenterTop(contents_bounds);
} else if (arrow_ == LEFT_CENTER) {
contents_bounds += RightCenter(anchor_rect) - LeftCenter(contents_bounds);
} else if (arrow_ == RIGHT_CENTER) {
@@ -303,7 +310,9 @@ int BubbleBorder::GetBorderThickness() const {
}
int BubbleBorder::GetBorderCornerRadius() const {
- return UseMaterialDesign() ? 2 : images_->corner_radius;
+ if (UseMaterialDesign())
+ return corner_radius_.value_or(kMaterialDesignCornerRadius);
+ return images_->corner_radius;
}
int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
@@ -338,6 +347,16 @@ void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
images_->border_thickness = border_interior_thickness;
}
+void BubbleBorder::Init() {
+ if (UseMaterialDesign()) {
+ // Harmony bubbles don't use arrows.
+ alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
+ arrow_paint_type_ = PAINT_NONE;
+ } else {
+ images_ = GetBorderImages(shadow_);
+ }
+}
+
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
if (UseMaterialDesign())
return PaintMd(view, canvas);
@@ -365,8 +384,11 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
}
gfx::Insets BubbleBorder::GetInsets() const {
- if (UseMaterialDesign())
- return (shadow_ == NO_ASSETS) ? gfx::Insets() : GetBorderAndShadowInsets();
+ if (UseMaterialDesign()) {
+ return (shadow_ == NO_ASSETS)
+ ? gfx::Insets()
+ : GetBorderAndShadowInsets(md_shadow_elevation_);
+ }
// The insets contain the stroke and shadow pixels outside the bubble fill.
const int inset = GetBorderThickness();
@@ -388,14 +410,20 @@ gfx::Size BubbleBorder::GetMinimumSize() const {
}
// static
-const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags() {
- // This object is always the same, so construct it once and cache.
- static const base::NoDestructor<cc::PaintFlags> flags([] {
- cc::PaintFlags f;
- constexpr SkColor kBorderColor = SkColorSetA(SK_ColorBLACK, 0x26);
- f.setColor(kBorderColor);
- f.setAntiAlias(true);
-
+const gfx::ShadowValues& BubbleBorder::GetShadowValues(
+ base::Optional<int> elevation) {
+ // The shadows are always the same for any elevation, so construct them once
+ // and cache.
+ static base::NoDestructor<std::map<int, gfx::ShadowValues>> shadow_map;
+ if (shadow_map->find(elevation.value_or(-1)) != shadow_map->end())
+ return shadow_map->find(elevation.value_or(-1))->second;
+
+ gfx::ShadowValues shadows;
+ if (elevation.has_value()) {
+ DCHECK(elevation.value() >= 0);
+ shadows = gfx::ShadowValues(
+ gfx::ShadowValue::MakeMdShadowValues(elevation.value()));
+ } else {
constexpr int kSmallShadowVerticalOffset = 2;
constexpr int kSmallShadowBlur = 4;
constexpr SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
@@ -403,15 +431,38 @@ const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags() {
// gfx::ShadowValue counts blur pixels both inside and outside the shape,
// whereas these blur values only describe the outside portion, hence they
// must be doubled.
- f.setLooper(gfx::CreateShadowDrawLooper({
+ shadows = gfx::ShadowValues({
{gfx::Vector2d(0, kSmallShadowVerticalOffset), 2 * kSmallShadowBlur,
kSmallShadowColor},
{gfx::Vector2d(0, kShadowVerticalOffset), 2 * kShadowBlur,
kLargeShadowColor},
- }));
- return f;
- }());
- return *flags;
+ });
+ }
+
+ shadow_map->insert(
+ std::pair<int, gfx::ShadowValues>(elevation.value_or(-1), shadows));
+ return shadow_map->find(elevation.value_or(-1))->second;
+}
+
+// static
+const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags(
+ base::Optional<int> elevation) {
+ // The flags are always the same for any elevation, so construct them once and
+ // cache.
+ static base::NoDestructor<std::map<int, cc::PaintFlags>> flag_map;
+
+ if (flag_map->find(elevation.value_or(-1)) != flag_map->end())
+ return flag_map->find(elevation.value_or(-1))->second;
+
+ cc::PaintFlags flags;
+ constexpr SkColor kBorderColor = SkColorSetA(SK_ColorBLACK, 0x26);
+ flags.setColor(kBorderColor);
+ flags.setAntiAlias(true);
+ flags.setLooper(gfx::CreateShadowDrawLooper(GetShadowValues(elevation)));
+ flag_map->insert(
+ std::pair<int, cc::PaintFlags>(elevation.value_or(-1), flags));
+
+ return flag_map->find(elevation.value_or(-1))->second;
}
gfx::Size BubbleBorder::GetSizeForContentsSize(
@@ -547,7 +598,8 @@ void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) {
canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference,
true /*doAntiAlias*/);
- DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas);
+ DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas,
+ md_shadow_elevation_);
}
void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) {
@@ -561,6 +613,11 @@ internal::BorderImages* BubbleBorder::GetImagesForTest() const {
return images_;
}
+bool BubbleBorder::UseMaterialDesign() const {
+ return ui::MaterialDesignController::IsSecondaryUiMaterial() ||
+ corner_radius_.has_value();
+}
+
void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
canvas->DrawColor(border_->background_color());
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 46531ed02f6..400366fd808 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -13,6 +13,7 @@
#include "build/build_config.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/shadow_value.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
@@ -172,26 +173,34 @@ class VIEWS_EXPORT BubbleBorder : public Border {
a : static_cast<Arrow>(a ^ BOTTOM);
}
- // Returns the insets required by a border and shadow. This is only used for
- // MD bubbles.
- static gfx::Insets GetBorderAndShadowInsets();
+ // Returns the insets required by a border and shadow based on
+ // |shadow_elevation|. This is only used for MD bubbles. A null
+ // |shadow_elevation| will yield the default BubbleBorder MD insets.
+ static gfx::Insets GetBorderAndShadowInsets(
+ base::Optional<int> shadow_elevation = base::nullopt);
- // Draws a border and shadow outside the |rect| on |canvas|, using |draw| as
- // the draw function. Templated so as to accept either SkRect or SkRRect.
+ // Draws a border and shadow based on |shadow_elevation| outside the |rect| on
+ // |canvas|, using |draw| as the draw function. Templated so as to accept
+ // either SkRect or SkRRect.
template <typename T>
static void DrawBorderAndShadow(
T rect,
void (cc::PaintCanvas::*draw)(const T&, const cc::PaintFlags&),
- gfx::Canvas* canvas) {
+ gfx::Canvas* canvas,
+ base::Optional<int> shadow_elevation = base::nullopt) {
// Provide a 1 px border outside the bounds.
const int kBorderStrokeThicknessPx = 1;
const SkScalar one_pixel =
SkFloatToScalar(kBorderStrokeThicknessPx / canvas->image_scale());
rect.outset(one_pixel, one_pixel);
- (canvas->sk_canvas()->*draw)(rect, GetBorderAndShadowFlags());
+ (canvas->sk_canvas()->*draw)(rect,
+ GetBorderAndShadowFlags(shadow_elevation));
}
+ // Set the corner radius, enables Material Design.
+ void SetCornerRadius(int radius);
+
// Get or set the arrow type.
void set_arrow(Arrow arrow) { arrow_ = arrow; }
Arrow arrow() const { return arrow_; }
@@ -221,9 +230,17 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// location to place the arrow |offset| pixels from the perpendicular edge.
void set_arrow_offset(int offset) { arrow_offset_ = offset; }
- // Sets the way the arrow is actually painted. Default is PAINT_NORMAL.
+ // Sets the way the arrow is actually painted. Default is PAINT_NORMAL.
void set_paint_arrow(ArrowPaintType value);
+ // Sets the shadow elevation for MD shadows. A null |shadow_elevation| will
+ // yield the default BubbleBorder MD shadow.
+ void set_md_shadow_elevation(int shadow_elevation) {
+ DCHECK(UseMaterialDesign()) << "Setting a non-default MD shadow elevation "
+ "requires that the BubbleBorder is using MD";
+ md_shadow_elevation_ = shadow_elevation;
+ }
+
// Get the desired widget bounds (in screen coordinates) given the anchor rect
// and bubble content size; calculated from shadow and arrow image dimensions.
virtual gfx::Rect GetBounds(const gfx::Rect& anchor_rect,
@@ -259,13 +276,25 @@ class VIEWS_EXPORT BubbleBorder : public Border {
FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest);
FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, ShadowTypes);
- // Returns the paint flags to use for painting the border and shadow. This is
- // only used for MD bubbles.
- static const cc::PaintFlags& GetBorderAndShadowFlags();
+ // Returns the shadows based on |shadow_elevation| to use for painting the
+ // border and shadow, and for getting insets. This is only used for MD
+ // bubbles. A null |shadow_elevation| will yield the default BubbleBorder MD
+ // ShadowValues.
+ static const gfx::ShadowValues& GetShadowValues(
+ base::Optional<int> shadow_elevation = base::nullopt);
+
+ // Returns the paint flags to use for painting the border and shadow based on
+ // |shadow_elevation|. This is only used for MD bubbles. A null
+ // |shadow_elevation| will yield the default BubbleBorder MD PaintFlags.
+ static const cc::PaintFlags& GetBorderAndShadowFlags(
+ base::Optional<int> shadow_elevation = base::nullopt);
// The border and arrow stroke size used in image assets, in pixels.
static const int kStroke;
+ // Initializes the MD or non-MD BubbleBorder.
+ void Init();
+
gfx::Size GetSizeForContentsSize(const gfx::Size& contents_size) const;
gfx::ImageSkia* GetArrowImage() const;
gfx::Rect GetArrowRect(const gfx::Rect& bounds) const;
@@ -287,8 +316,16 @@ class VIEWS_EXPORT BubbleBorder : public Border {
internal::BorderImages* GetImagesForTest() const;
+ // Whether to use material design.
+ bool UseMaterialDesign() const;
+
Arrow arrow_;
int arrow_offset_;
+ // Corner radius for the bubble border. If supplied the border will use
+ // material design.
+ base::Optional<int> corner_radius_;
+ // Elevation for the MD shadow. Requires material design.
+ base::Optional<SkColor> md_shadow_elevation_;
ArrowPaintType arrow_paint_type_;
BubbleAlignment alignment_;
Shadow shadow_;
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index adb23135acf..87ca9bc7786 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -423,9 +423,8 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
: kAnchor.x() + kStrokeWidth - kBorderThickness,
kTopHorizArrowY},
{BubbleBorder::TOP_CENTER, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- UseMd() ? kAnchor.CenterPoint().x()
- : kAnchor.CenterPoint().x() - kArrowOffsetForHorizCenter,
- kTopHorizArrowY + (UseMd() ? kInsets.top() - kStrokeWidth : 0)},
+ kAnchor.CenterPoint().x() - kArrowOffsetForHorizCenter,
+ kTopHorizArrowY},
{BubbleBorder::BOTTOM_RIGHT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
UseMd() ? kAnchor.CenterPoint().x() - kTotalSizeWithHorizArrow.width()
: kAnchor.CenterPoint().x() + kArrowOffsetForNotCenter -
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.cc b/chromium/ui/views/bubble/bubble_dialog_delegate.cc
index 9f766e72100..5856ea9b8b1 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate.cc
@@ -4,7 +4,6 @@
#include "ui/views/bubble/bubble_dialog_delegate.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
@@ -38,6 +37,10 @@ Widget* CreateBubbleWidget(BubbleDialogDelegateView* bubble) {
bubble_params.delegate = bubble;
bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
bubble_params.accept_events = bubble->accept_events();
+ // Use a window default shadow if the bubble doesn't provides its own.
+ bubble_params.shadow_type = bubble->shadow() == BubbleBorder::NO_ASSETS
+ ? Widget::InitParams::SHADOW_TYPE_DEFAULT
+ : Widget::InitParams::SHADOW_TYPE_NONE;
if (bubble->parent_window())
bubble_params.parent = bubble->parent_window();
else if (bubble->anchor_widget())
@@ -47,8 +50,13 @@ Widget* CreateBubbleWidget(BubbleDialogDelegateView* bubble) {
: Widget::InitParams::ACTIVATABLE_NO;
bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget);
bubble_widget->Init(bubble_params);
+#if !defined(OS_MACOSX)
+ // On Mac, having a parent window creates a permanent stacking order, so
+ // there's no need to do this. Also, calling StackAbove() on Mac shows the
+ // bubble implicitly, for which the bubble is currently not ready.
if (bubble_params.parent)
bubble_widget->StackAbove(bubble_params.parent);
+#endif
return bubble_widget;
}
@@ -214,14 +222,15 @@ BubbleDialogDelegateView::BubbleDialogDelegateView()
: BubbleDialogDelegateView(nullptr, BubbleBorder::TOP_LEFT) {}
BubbleDialogDelegateView::BubbleDialogDelegateView(View* anchor_view,
- BubbleBorder::Arrow arrow)
+ BubbleBorder::Arrow arrow,
+ BubbleBorder::Shadow shadow)
: close_on_deactivate_(true),
anchor_view_tracker_(std::make_unique<ViewTracker>()),
anchor_widget_(nullptr),
arrow_(arrow),
mirror_arrow_in_rtl_(
ViewsDelegate::GetInstance()->ShouldMirrorArrowsInRTL()),
- shadow_(BubbleBorder::DIALOG_SHADOW),
+ shadow_(shadow),
color_explicitly_set_(false),
accept_events_(true),
adjust_if_offscreen_(true),
@@ -250,6 +259,13 @@ gfx::Rect BubbleDialogDelegateView::GetBubbleBounds() {
adjust_if_offscreen_ && !anchor_minimized && has_anchor);
}
+ax::mojom::Role BubbleDialogDelegateView::GetAccessibleWindowRole() const {
+ // We return |ax::mojom::Role::kAlertDialog| which will make screen
+ // readers announce the contents of the bubble dialog as soon as it appears,
+ // as long as we also fire |ax::mojom::Event::kAlert|.
+ return ax::mojom::Role::kAlertDialog;
+}
+
void BubbleDialogDelegateView::OnNativeThemeChanged(
const ui::NativeTheme* theme) {
UpdateColorsFromTheme(theme);
@@ -325,9 +341,11 @@ void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget,
// the bubble in its entirety rather than just its title and initially focused
// view. See http://crbug.com/474622 for details.
if (widget == GetWidget() && visible) {
- if (GetAccessibleWindowRole() == ax::mojom::Role::kAlertDialog)
+ if (GetAccessibleWindowRole() == ax::mojom::Role::kAlert ||
+ GetAccessibleWindowRole() == ax::mojom::Role::kAlertDialog) {
widget->GetRootView()->NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
true);
+ }
}
}
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.h b/chromium/ui/views/bubble/bubble_dialog_delegate.h
index ab5ca68d283..fa45ae39055 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate.h
@@ -10,6 +10,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "build/build_config.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
@@ -127,11 +128,20 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
protected:
BubbleDialogDelegateView();
- BubbleDialogDelegateView(View* anchor_view, BubbleBorder::Arrow arrow);
+ // |shadow| usually doesn't need to be explicitly set, just uses the default
+ // argument. Unless on Mac when the bubble needs to use Views base shadow,
+ // override it with suitable bubble border type.
+ BubbleDialogDelegateView(
+ View* anchor_view,
+ BubbleBorder::Arrow arrow,
+ BubbleBorder::Shadow shadow = BubbleBorder::DIALOG_SHADOW);
// Get bubble bounds from the anchor rect and client view's preferred size.
virtual gfx::Rect GetBubbleBounds();
+ // DialogDelegateView overrides:
+ ax::mojom::Role GetAccessibleWindowRole() const override;
+
// View overrides:
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
diff --git a/chromium/ui/views/bubble/info_bubble.cc b/chromium/ui/views/bubble/info_bubble.cc
index b17c6db9872..65fc0411ece 100644
--- a/chromium/ui/views/bubble/info_bubble.cc
+++ b/chromium/ui/views/bubble/info_bubble.cc
@@ -11,6 +11,7 @@
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/layout_provider.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -20,10 +21,6 @@ namespace {
// The visible width of bubble borders (differs from the actual width) in px.
const int kBubbleBorderVisibleWidth = 1;
-// The margin between the content of the error bubble and its border.
-const int kInfoBubbleHorizontalMargin = 14;
-const int kInfoBubbleVerticalMargin = 12;
-
} // namespace
class InfoBubbleFrame : public BubbleFrameView {
@@ -52,8 +49,8 @@ InfoBubble::InfoBubble(View* anchor, const base::string16& message)
DCHECK(anchor_);
SetAnchorView(anchor_);
- set_margins(
- gfx::Insets(kInfoBubbleVerticalMargin, kInfoBubbleHorizontalMargin));
+ set_margins(LayoutProvider::Get()->GetInsetsMetric(
+ InsetsMetric::INSETS_TOOLTIP_BUBBLE));
set_can_activate(false);
SetLayoutManager(std::make_unique<FillLayout>());
diff --git a/chromium/ui/views/bubble/tooltip_icon.cc b/chromium/ui/views/bubble/tooltip_icon.cc
index de30b6dcc62..b25fd527510 100644
--- a/chromium/ui/views/bubble/tooltip_icon.cc
+++ b/chromium/ui/views/bubble/tooltip_icon.cc
@@ -4,7 +4,6 @@
#include "ui/views/bubble/tooltip_icon.h"
-#include "base/memory/ptr_util.h"
#include "base/timer/timer.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/accessibility/ax_node_data.h"
diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc
index fe4ba9727f6..1a5f43ef3df 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.cc
+++ b/chromium/ui/views/bubble/tray_bubble_view.cc
@@ -150,7 +150,8 @@ TrayBubbleView::InitParams::InitParams(const InitParams& other) = default;
TrayBubbleView::RerouteEventHandler::RerouteEventHandler(
TrayBubbleView* tray_bubble_view)
: tray_bubble_view_(tray_bubble_view) {
- aura::Env::GetInstance()->PrependPreTargetHandler(this);
+ aura::Env::GetInstance()->AddPreTargetHandler(
+ this, ui::EventTarget::Priority::kSystem);
}
TrayBubbleView::RerouteEventHandler::~RerouteEventHandler() {
@@ -210,7 +211,8 @@ TrayBubbleView::TrayBubbleView(const InitParams& init_params)
preferred_width_(init_params.min_width),
bubble_border_(new BubbleBorder(
arrow(),
- BubbleBorder::NO_ASSETS,
+ init_params.has_shadow ? BubbleBorder::NO_ASSETS
+ : BubbleBorder::NO_SHADOW,
init_params.bg_color.value_or(gfx::kPlaceholderColor))),
owned_bubble_border_(bubble_border_),
is_gesture_dragging_(false),
@@ -221,6 +223,8 @@ TrayBubbleView::TrayBubbleView(const InitParams& init_params)
bubble_border_->set_use_theme_background_color(!init_params.bg_color);
bubble_border_->set_alignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
bubble_border_->set_paint_arrow(BubbleBorder::PAINT_NONE);
+ if (init_params.corner_radius)
+ bubble_border_->SetCornerRadius(init_params.corner_radius.value());
set_parent_window(params_.parent_window);
set_can_activate(false);
set_notify_enter_exit_on_child(true);
@@ -313,6 +317,13 @@ int TrayBubbleView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
+ax::mojom::Role TrayBubbleView::GetAccessibleWindowRole() const {
+ // We override the role because the base class sets it to alert dialog.
+ // This would make screen readers announce the whole of the system tray
+ // which is undesirable.
+ return ax::mojom::Role::kDialog;
+}
+
void TrayBubbleView::SizeToContents() {
BubbleDialogDelegateView::SizeToContents();
bubble_content_mask_->layer()->SetBounds(GetBubbleBounds());
@@ -320,9 +331,11 @@ void TrayBubbleView::SizeToContents() {
void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
Widget* bubble_widget) const {
- // Apply a WM-provided shadow (see ui/wm/core/).
- params->shadow_type = Widget::InitParams::SHADOW_TYPE_DROP;
- params->shadow_elevation = wm::kShadowElevationActiveWindow;
+ if (bubble_border_->shadow() == BubbleBorder::NO_ASSETS) {
+ // Apply a WM-provided shadow (see ui/wm/core/).
+ params->shadow_type = Widget::InitParams::SHADOW_TYPE_DROP;
+ params->shadow_elevation = wm::kShadowElevationActiveWindow;
+ }
}
void TrayBubbleView::OnWidgetClosing(Widget* widget) {
diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h
index aeff9a874a0..92f3ed00638 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.h
+++ b/chromium/ui/views/bubble/tray_bubble_view.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/optional.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/events/event.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/bubble/bubble_dialog_delegate.h"
@@ -95,6 +96,8 @@ class VIEWS_EXPORT TrayBubbleView : public BubbleDialogDelegateView,
bool show_by_click = false;
// If not provided, the bg color will be derived from the NativeTheme.
base::Optional<SkColor> bg_color;
+ base::Optional<int> corner_radius;
+ bool has_shadow = true;
};
explicit TrayBubbleView(const InitParams& init_params);
@@ -160,6 +163,7 @@ class VIEWS_EXPORT TrayBubbleView : public BubbleDialogDelegateView,
protected:
// Overridden from views::BubbleDialogDelegateView.
int GetDialogButtons() const override;
+ ax::mojom::Role GetAccessibleWindowRole() const override;
void SizeToContents() override;
// Overridden from views::View.
diff --git a/chromium/ui/views/cocoa/OWNERS b/chromium/ui/views/cocoa/OWNERS
index 13c6f49f974..50a55e521ee 100644
--- a/chromium/ui/views/cocoa/OWNERS
+++ b/chromium/ui/views/cocoa/OWNERS
@@ -1 +1,2 @@
tapted@chromium.org
+ellyjones@chromium.org
diff --git a/chromium/ui/views/cocoa/bridged_content_view.h b/chromium/ui/views/cocoa/bridged_content_view.h
index c04515dd324..bb53eab7765 100644
--- a/chromium/ui/views/cocoa/bridged_content_view.h
+++ b/chromium/ui/views/cocoa/bridged_content_view.h
@@ -49,9 +49,6 @@ class View;
// that OSX correctly blurs the background showing through.
BOOL drawMenuBackgroundForBlur_;
- // Whether dragging on the view moves the window.
- BOOL mouseDownCanMoveWindow_;
-
// The cached window mask. Only used for non-rectangular windows on 10.9.
base::scoped_nsobject<NSBezierPath> windowMask_;
}
@@ -60,11 +57,6 @@ class View;
@property(assign, nonatomic) ui::TextInputClient* textInputClient;
@property(assign, nonatomic) BOOL drawMenuBackgroundForBlur;
-// Extends an atomic, readonly property on NSView to make it assignable.
-// This usually returns YES if the view is transparent. We want to control it
-// so that BridgedNativeWidget can dynamically enable dragging of the window.
-@property(assign) BOOL mouseDownCanMoveWindow;
-
// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
- (id)initWithView:(views::View*)viewToHost;
diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm
index 5faee65a24f..c55fb600d20 100644
--- a/chromium/ui/views/cocoa/bridged_content_view.mm
+++ b/chromium/ui/views/cocoa/bridged_content_view.mm
@@ -14,6 +14,7 @@
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data_provider_mac.h"
+#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
@@ -24,6 +25,7 @@
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "ui/gfx/canvas_paint_mac.h"
#include "ui/gfx/decorated_text.h"
+#import "ui/gfx/decorated_text_mac.h"
#include "ui/gfx/geometry/rect.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/gfx/path.h"
@@ -200,42 +202,6 @@ base::string16 AttributedSubstringForRangeHelper(
return substring;
}
-NSAttributedString* GetAttributedString(
- const gfx::DecoratedText& decorated_text) {
- base::scoped_nsobject<NSMutableAttributedString> str(
- [[NSMutableAttributedString alloc]
- initWithString:base::SysUTF16ToNSString(decorated_text.text)]);
- [str beginEditing];
-
- NSValue* const line_style =
- @(NSUnderlineStyleSingle | NSUnderlinePatternSolid);
-
- for (const auto& attribute : decorated_text.attributes) {
- DCHECK(!attribute.range.is_reversed());
- DCHECK_LE(attribute.range.end(), [str length]);
-
- NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
- NSRange range = attribute.range.ToNSRange();
-
- if (attribute.font.GetNativeFont())
- attrs[NSFontAttributeName] = attribute.font.GetNativeFont();
-
- // NSFont does not have underline as an attribute. Hence handle it
- // separately.
- const bool underline = attribute.font.GetStyle() & gfx::Font::UNDERLINE;
- if (underline)
- attrs[NSUnderlineStyleAttributeName] = line_style;
-
- if (attribute.strike)
- attrs[NSStrikethroughStyleAttributeName] = line_style;
-
- [str setAttributes:attrs range:range];
- }
-
- [str endEditing];
- return str.autorelease();
-}
-
ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (action == @selector(undo:))
return ui::TextEditCommand::UNDO;
@@ -309,7 +275,6 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@synthesize hostedView = hostedView_;
@synthesize textInputClient = textInputClient_;
@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
-@synthesize mouseDownCanMoveWindow = mouseDownCanMoveWindow_;
- (id)initWithView:(views::View*)viewToHost {
DCHECK(viewToHost);
@@ -356,6 +321,16 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
[self removeTrackingArea:cursorTrackingArea_.get()];
}
+// If the point is classified as HTCAPTION (background, draggable), return nil
+// so that it can lead to a window drag or double-click in the title bar.
+- (NSView*)hitTest:(NSPoint)point {
+ gfx::Point flippedPoint(point.x, NSHeight(self.superview.bounds) - point.y);
+ int component = hostedView_->GetWidget()->GetNonClientComponent(flippedPoint);
+ if (component == HTCAPTION)
+ return nil;
+ return [super hitTest:point];
+}
+
- (void)processCapturedMouseEvent:(NSEvent*)theEvent {
if (!hostedView_)
return;
@@ -649,11 +624,16 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// NSView implementation.
-// Always refuse first responder. Note this does not prevent the view becoming
-// first responder via -[NSWindow makeFirstResponder:] when invoked during Init
-// or by FocusManager.
+// Refuse first responder, unless we are already first responder. Note this does
+// not prevent the view becoming first responder via -[NSWindow
+// makeFirstResponder:] when invoked during Init or by FocusManager.
+//
+// The condition is to work around an AppKit quirk. When a window is being
+// ordered front, if its current first responder returns |NO| for this method,
+// it resigns it if it can find another responder in the key loop that replies
+// |YES|.
- (BOOL)acceptsFirstResponder {
- return NO;
+ return [[self window] firstResponder] == self;
}
- (BOOL)becomeFirstResponder {
@@ -850,6 +830,11 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
[self handleKeyEvent:&event];
}
+- (void)flagsChanged:(NSEvent*)theEvent {
+ ui::KeyEvent event(theEvent);
+ [self handleKeyEvent:&event];
+}
+
- (void)scrollWheel:(NSEvent*)theEvent {
if (!hostedView_)
return;
@@ -904,7 +889,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
views::View::ConvertPointToTarget(hostedView_, target, &locationInTarget);
gfx::DecoratedText decoratedWord;
gfx::Point baselinePoint;
- if (!wordLookupClient->GetDecoratedWordAtPoint(
+ if (!wordLookupClient->GetWordLookupDataAtPoint(
locationInTarget, &decoratedWord, &baselinePoint)) {
return;
}
@@ -913,7 +898,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
views::View::ConvertPointToTarget(target, hostedView_, &baselinePoint);
NSPoint baselinePointAppKit = NSMakePoint(
baselinePoint.x(), NSHeight([self frame]) - baselinePoint.y());
- [self showDefinitionForAttributedString:GetAttributedString(decoratedWord)
+ [self showDefinitionForAttributedString:
+ gfx::GetAttributedStringFromDecoratedText(decoratedWord)
atPoint:baselinePointAppKit];
}
@@ -1464,16 +1450,16 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
composition.text = base::SysNSStringToUTF16(text);
composition.selection = gfx::Range(selectedRange);
- // Add a black underline with a transparent background to the composition
- // text. TODO(karandeepb): On Cocoa textfields, the target clause of the
- // composition has a thick underlines. The composition text also has
+ // Add an underline with text color and a transparent background to the
+ // composition text. TODO(karandeepb): On Cocoa textfields, the target clause
+ // of the composition has a thick underlines. The composition text also has
// discontinous underlines for different clauses. This is also supported in
// the Chrome renderer. Add code to extract underlines from |text| once our
// render text implementation supports thick underlines and discontinous
// underlines for consecutive characters. See http://crbug.com/612675.
composition.ime_text_spans.push_back(
ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, [text length],
- SK_ColorBLACK, false, SK_ColorTRANSPARENT));
+ ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
textInputClient_->SetCompositionText(composition);
hasUnhandledKeyDownEvent_ = NO;
}
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h
index 64be7882515..9af5c2db7db 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget.h
@@ -71,10 +71,6 @@ class VIEWS_EXPORT BridgedNativeWidget
static gfx::Size GetWindowSizeForClientSize(NSWindow* window,
const gfx::Size& size);
- // Whether an event monitor should be used to intercept window drag events.
- // Evalutes to |true| on macOS 10.10 and older.
- static bool ShouldUseDragEventMonitor();
-
// Creates one side of the bridge. |parent| must not be NULL.
explicit BridgedNativeWidget(NativeWidgetMac* parent);
~BridgedNativeWidget() override;
@@ -162,17 +158,6 @@ class VIEWS_EXPORT BridgedNativeWidget
// Called by the NSWindowDelegate when the window becomes or resigns key.
void OnWindowKeyStatusChangedTo(bool is_key);
- // Returns true if the |event| should initiate a window drag.
- bool ShouldDragWindow(NSEvent* event);
-
- // Called when the application receives a mouse-down, but before the event is
- // processed by NSWindow. Returning true here will cause the event to be
- // cancelled and reposted at the CGSessionEventTap level. This is used to
- // determine whether a mouse-down should drag the window. Only called when
- // ShouldUseDragEventMonitor() returns true.
- // Virtual for testing.
- virtual bool ShouldRepostPendingLeftMouseDown(NSEvent* event);
-
// Called by NativeWidgetMac when the window size constraints change.
void OnSizeConstraintsChanged();
@@ -264,13 +249,6 @@ class VIEWS_EXPORT BridgedNativeWidget
// Show the window using -[NSApp beginSheet:..], modal for the parent window.
void ShowAsModalSheet();
- // Sets mouseDownCanMoveWindow on |bridged_view_| and triggers the NSWindow to
- // update its draggable region.
- void SetDraggable(bool draggable);
-
- // Called by |mouse_down_monitor_| to close a bubble.
- void OnRightMouseDownWithBubble(NSEvent* event);
-
// Overridden from CocoaMouseCaptureDelegate:
void PostCapturedEvent(NSEvent* event) override;
void OnMouseCaptureLost() override;
@@ -360,9 +338,6 @@ class VIEWS_EXPORT BridgedNativeWidget
// the compositor arrives to avoid "blinking".
bool initial_visibility_suppressed_ = false;
- // Right mouse down monitor for bubble widget.
- id mouse_down_monitor_;
-
AssociatedViews associated_views_;
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget);
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm
index 3c6e9903d7d..64ea16b86ef 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget.mm
@@ -12,7 +12,6 @@
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#import "base/mac/sdk_forward_declarations.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/features.h"
@@ -126,15 +125,6 @@ using NSViewComparatorValue = id;
using NSViewComparatorValue = __kindof NSView*;
#endif
-const CGFloat kMavericksMenuOpacity = 251.0 / 255.0;
-const CGFloat kYosemiteMenuOpacity = 177.0 / 255.0;
-const int kYosemiteMenuBlur = 80;
-
-// Margin at edge and corners of the window that trigger resizing. These match
-// actual Cocoa resize margins.
-const int kResizeAreaEdgeSize = 3;
-const int kResizeAreaCornerSize = 12;
-
int kWindowPropertiesKey;
float GetDeviceScaleFactorFromView(NSView* view) {
@@ -178,141 +168,6 @@ gfx::Size GetClientSizeForWindowSize(NSWindow* window,
return gfx::Size([window contentRectForFrameRect:frame_rect].size);
}
-// Determine whether a point is within the resize area at the edges and corners
-// of a window. This is used to ensure that mouse downs which would resize the
-// window are not reposted. As there's no way to determine this from Cocoa APIs,
-// this should aim to match Cocoa behavior as closely as possible.
-bool IsPointInResizeArea(NSPoint point, NSWindow* window) {
- if (!([window styleMask] & NSResizableWindowMask))
- return false;
-
- bool can_resize_x = [window maxSize].width > [window minSize].width;
- bool can_resize_y = [window maxSize].height > [window minSize].height;
- NSSize window_size = [window frame].size;
-
- if (can_resize_x && (point.x < kResizeAreaEdgeSize ||
- point.x >= window_size.width - kResizeAreaEdgeSize))
- return true;
-
- if (can_resize_y && (point.y < kResizeAreaEdgeSize ||
- point.y >= window_size.height - kResizeAreaEdgeSize))
- return true;
-
- if (can_resize_x && can_resize_y &&
- (point.x < kResizeAreaCornerSize ||
- point.x >= window_size.width - kResizeAreaCornerSize) &&
- (point.y < kResizeAreaCornerSize ||
- point.y >= window_size.height - kResizeAreaCornerSize))
- return true;
-
- return false;
-}
-
-// Routes the |ns_event| to the corresponding BridgedNativeWidget and queries
-// whether the event should be reposted.
-BOOL WindowWantsMouseDownReposted(NSEvent* ns_event) {
- DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
-
- views::BridgedNativeWidget* bridge =
- views::NativeWidgetMac::GetBridgeForNativeWindow([ns_event window]);
- return bridge && bridge->ShouldRepostPendingLeftMouseDown(ns_event);
-}
-
-// Check if a mouse-down event should drag the window. If so, repost the event.
-NSEvent* RepostEventIfHandledByWindow(NSEvent* ns_event) {
- DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
-
- enum RepostState {
- // Nothing reposted: hit-test new mouse-downs to see if they need to be
- // ignored and reposted after changing draggability.
- NONE,
- // Expecting the next event to be the reposted event: let it go through.
- EXPECTING_REPOST,
- // If, while reposting, another mousedown was received: when the reposted
- // event is seen, ignore it.
- REPOST_CANCELLED,
- };
-
- // Which repost we're expecting to receive.
- static RepostState repost_state = NONE;
- // The event number of the reposted event. This let's us track whether an
- // event is actually the repost since user-generated events have increasing
- // event numbers. This is only valid while |repost_state != NONE|.
- static NSInteger reposted_event_number;
-
- NSInteger event_number = [ns_event eventNumber];
-
- // The logic here is a bit convoluted because we want to mitigate race
- // conditions if somehow a different mouse-down occurs between reposts.
- // Specifically, we want to avoid:
- // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is
- // draggable outside of a repost cycle),
- // - any repost loop.
-
- if (repost_state == NONE) {
- if (WindowWantsMouseDownReposted(ns_event)) {
- repost_state = EXPECTING_REPOST;
- reposted_event_number = event_number;
- CGEventPost(kCGSessionEventTap, [ns_event CGEvent]);
- return nil;
- }
-
- return ns_event;
- }
-
- if (repost_state == EXPECTING_REPOST) {
- // Call through so that the window is made non-draggable again.
- WindowWantsMouseDownReposted(ns_event);
-
- if (reposted_event_number == event_number) {
- // Reposted event received.
- repost_state = NONE;
- return nil;
- }
-
- // We were expecting a repost, but since this is a new mouse-down, cancel
- // reposting and allow event to continue as usual.
- repost_state = REPOST_CANCELLED;
- return ns_event;
- }
-
- DCHECK_EQ(REPOST_CANCELLED, repost_state);
- if (reposted_event_number == event_number) {
- // Reposting was cancelled, now that we've received the event, we don't
- // expect to see it again.
- repost_state = NONE;
- return nil;
- }
-
- return ns_event;
-}
-
-// Support window caption/draggable regions.
-// In AppKit, non-client regions are set by overriding
-// -[NSView mouseDownCanMoveWindow]. NSApplication caches this area as views are
-// installed and performs window moving when mouse-downs land in the area.
-// In Views, non-client regions are determined via hit-tests when the event
-// occurs.
-// To bridge the two models, we monitor mouse-downs with
-// +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. This receives
-// events after window dragging is handled, so for mouse-downs that land on a
-// draggable point, we cancel the event, make the window draggable and repost it
-// at the CGSessionEventTap level so that window dragging will be handled again.
-// On Mac OS > 10.10, we don't use an event monitor. Instead, we use [NSWindow
-// performWindowDragWithEvent:]. See [NativeWidgetMacNSWindow sendEvent:].
-void SetupDragEventMonitor() {
- DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
- static id monitor = nil;
- if (monitor)
- return;
-
- monitor = [NSEvent
- addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
- handler:^NSEvent*(NSEvent* ns_event) {
- return RepostEventIfHandledByWindow(ns_event);
- }];
-}
-
// Returns a task runner for creating a ui::Compositor. This allows compositor
// tasks to be funneled through ui::WindowResizeHelper's task runner to allow
// resize operations to coordinate with frames provided by the GPU process.
@@ -384,13 +239,6 @@ gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize(
return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
}
-// static
-// TODO(karandeepb): Remove usage of drag event monitor once we stop supporting
-// Mac OS 10.10.
-bool BridgedNativeWidget::ShouldUseDragEventMonitor() {
- return base::mac::IsAtMostOS10_10();
-}
-
BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
: native_widget_mac_(parent),
focus_manager_(nullptr),
@@ -399,11 +247,7 @@ BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
target_fullscreen_state_(false),
in_fullscreen_transition_(false),
window_visible_(false),
- wants_to_be_visible_(false),
- mouse_down_monitor_(nullptr) {
- if (BridgedNativeWidget::ShouldUseDragEventMonitor())
- SetupDragEventMonitor();
-
+ wants_to_be_visible_(false) {
DCHECK(parent);
window_delegate_.reset(
[[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
@@ -448,17 +292,6 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
name:NSControlTintDidChangeNotification
object:nil];
- // Right-clicks outside a bubble should dismiss them, but that doesn't cause
- // loss of focus on Mac, so add an event monitor to detect.
- if (params.type == Widget::InitParams::TYPE_BUBBLE) {
- mouse_down_monitor_ = [NSEvent
- addLocalMonitorForEventsMatchingMask:NSRightMouseDownMask
- handler:^NSEvent* (NSEvent* event) {
- OnRightMouseDownWithBubble(event);
- return event;
- }];
- }
-
// Validate the window's initial state, otherwise the bridge's initial
// tracking state will be incorrect.
DCHECK(![window_ isVisible]);
@@ -798,10 +631,6 @@ void BridgedNativeWidget::OnWindowWillClose() {
parent_ = nullptr;
}
[[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
- if (mouse_down_monitor_) {
- [NSEvent removeMonitor:mouse_down_monitor_];
- mouse_down_monitor_ = nullptr;
- }
[show_animation_ stopAnimation]; // If set, calls OnShowAnimationComplete().
DCHECK(!show_animation_);
@@ -976,7 +805,8 @@ void BridgedNativeWidget::OnBackingPropertiesChanged() {
void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) {
Widget* widget = native_widget_mac()->GetWidget();
- widget->OnNativeWidgetActivationChanged(is_key);
+ if (!widget->OnNativeWidgetActivationChanged(is_key))
+ return;
// The contentView is the BridgedContentView hosting the views::RootView. The
// focus manager will already know if a native subview has focus.
if ([window_ contentView] == [window_ firstResponder]) {
@@ -993,56 +823,6 @@ void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) {
}
}
-bool BridgedNativeWidget::ShouldDragWindow(NSEvent* event) {
- if (!bridged_view_ || [event type] != NSLeftMouseDown)
- return false;
-
- NSPoint location_in_window = [event locationInWindow];
- if (IsPointInResizeArea(location_in_window, window_))
- return false;
-
- gfx::Point point(location_in_window.x,
- NSHeight([window_ frame]) - location_in_window.y);
-
- if (native_widget_mac()->GetWidget()->GetNonClientComponent(point) !=
- HTCAPTION)
- return false;
-
- // Check that the point is not obscured by non-content NSViews.
- for (NSView* subview : [[bridged_view_ superview] subviews]) {
- if (subview == bridged_view_.get())
- continue;
-
- if (![subview mouseDownCanMoveWindow] &&
- NSPointInRect(location_in_window, [subview frame]))
- return false;
- }
-
- return true;
-}
-
-bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(NSEvent* event) {
- DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor());
- DCHECK_EQ(NSLeftMouseDown, [event type]);
-
- if (!bridged_view_)
- return false;
-
- if ([bridged_view_ mouseDownCanMoveWindow]) {
- // This is a re-post, the movement has already started, so we can make the
- // window non-draggable again.
- SetDraggable(false);
- return false;
- }
-
- if (!ShouldDragWindow(event))
- return false;
-
- // Make the window draggable, then return true to repost the event.
- SetDraggable(true);
- return true;
-}
-
void BridgedNativeWidget::OnSizeConstraintsChanged() {
// Don't modify the size constraints or fullscreen collection behavior while
// in fullscreen or during a transition. OnFullscreenTransitionComplete will
@@ -1465,22 +1245,6 @@ void BridgedNativeWidget::AddCompositorSuperview() {
[background_layer
setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
- if (widget_type_ == Widget::InitParams::TYPE_MENU) {
- // Giving the canvas opacity messes up subpixel font rendering, so use a
- // solid background, but make the CALayer transparent.
- if (base::mac::IsAtLeastOS10_10()) {
- [background_layer setOpacity:kYosemiteMenuOpacity];
- CGSSetWindowBackgroundBlurRadius(
- _CGSDefaultConnection(), [window_ windowNumber], kYosemiteMenuBlur);
- // The blur effect does not occur with a fully transparent (or fully
- // layer-backed) window. Setting a window background will use square
- // corners, so ask the contentView to draw one instead.
- [bridged_view_ setDrawMenuBackgroundForBlur:YES];
- } else {
- [background_layer setOpacity:kMavericksMenuOpacity];
- }
- }
-
// Set the layer first to create a layer-hosting view (not layer-backed).
[compositor_superview_ setLayer:background_layer];
[compositor_superview_ setWantsLayer:YES];
@@ -1565,38 +1329,4 @@ NSMutableDictionary* BridgedNativeWidget::GetWindowProperties() const {
return properties;
}
-void BridgedNativeWidget::SetDraggable(bool draggable) {
- DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor());
-
- [bridged_view_ setMouseDownCanMoveWindow:draggable];
- // AppKit will not update its cache of mouseDownCanMoveWindow unless something
- // changes. Previously we tried adding an NSView and removing it, but for some
- // reason it required reposting the mouse-down event, and didn't always work.
- // Calling the below seems to be an effective solution.
- [window_ setMovableByWindowBackground:NO];
- [window_ setMovableByWindowBackground:YES];
-}
-
-void BridgedNativeWidget::OnRightMouseDownWithBubble(NSEvent* event) {
- NSWindow* target = [event window];
- if ([target isSheet])
- return;
-
- // Do not close the bubble if the event happened on a window with a higher
- // level. For example, the content of a browser action bubble opens a
- // calendar picker window with NSPopUpMenuWindowLevel, and a date selection
- // closes the picker window, but it should not close the bubble.
- if ([target level] > [window_ level])
- return;
-
- // If the event is in |window_|'s hierarchy, do not close the bubble.
- while (target) {
- if (target == window_.get())
- return;
- target = [target parentWindow];
- }
-
- OnWindowKeyStatusChangedTo(false);
-}
-
} // namespace views
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
index 224ea14d0f1..f02e1b94c08 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -192,40 +192,6 @@ TEST_F(BridgedNativeWidgetUITest, FullscreenRestore) {
namespace {
-// This is used to wait for reposted events to be seen. We can't just use
-// RunPendingMessages() because CGEventPost might not be synchronous.
-class HitTestBridgedNativeWidget : public BridgedNativeWidget {
- public:
- explicit HitTestBridgedNativeWidget(NativeWidgetMac* widget)
- : BridgedNativeWidget(widget) {}
-
- // BridgedNativeWidget:
- bool ShouldRepostPendingLeftMouseDown(NSEvent* event) override {
- did_repost_ = BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(event);
-
- if (run_loop_)
- run_loop_->Quit();
-
- return did_repost_;
- }
-
- void WaitForShouldRepost() {
- base::RunLoop run_loop;
- run_loop_ = &run_loop;
- run_loop.Run();
- run_loop_ = nullptr;
- }
-
- bool IsDraggable() { return [ns_view() mouseDownCanMoveWindow]; }
- bool did_repost() { return did_repost_; }
-
- private:
- base::RunLoop* run_loop_ = nullptr;
- bool did_repost_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(HitTestBridgedNativeWidget);
-};
-
// This is used to return a customized result to NonClientHitTest.
class HitTestNonClientFrameView : public NativeFrameView {
public:
@@ -290,12 +256,7 @@ class HitTestNativeWidgetMac : public NativeWidgetMac {
HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate,
NativeFrameView* native_frame_view)
: NativeWidgetMac(delegate), native_frame_view_(native_frame_view) {
- NativeWidgetMac::bridge_.reset(new HitTestBridgedNativeWidget(this));
- }
-
- HitTestBridgedNativeWidget* bridge() {
- return static_cast<HitTestBridgedNativeWidget*>(
- NativeWidgetMac::bridge_.get());
+ NativeWidgetMac::bridge_.reset(new BridgedNativeWidget(this));
}
// internal::NativeWidgetPrivate:
@@ -345,11 +306,6 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
// mouse events.
[window setIgnoresMouseEvents:NO];
- HitTestBridgedNativeWidget* bridge = native_widget->bridge();
-
- const bool using_drag_event_monitor =
- BridgedNativeWidget::ShouldUseDragEventMonitor();
-
// Dragging the window should work.
frame_view->set_hit_test_result(HTCAPTION);
{
@@ -360,18 +316,8 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
initForNotification:NSWindowWillMoveNotification]);
NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
NSMakePoint(20, 20), window);
- EXPECT_FALSE(bridge->IsDraggable());
CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
- if (using_drag_event_monitor) {
- bridge->WaitForShouldRepost();
- EXPECT_TRUE(bridge->did_repost());
- EXPECT_TRUE(bridge->IsDraggable());
- bridge->WaitForShouldRepost();
- EXPECT_FALSE(bridge->did_repost());
- EXPECT_FALSE(bridge->IsDraggable());
- } else {
- WaitForEvent(NSLeftMouseDownMask);
- }
+ WaitForEvent(NSLeftMouseDownMask);
base::scoped_nsobject<WindowedNSNotificationObserver> did_move_observer(
[[WindowedNSNotificationObserver alloc]
@@ -402,18 +348,8 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
initForNotification:NSWindowWillMoveNotification]);
NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
bottom_right_point, window);
- EXPECT_FALSE(bridge->IsDraggable());
CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
- if (using_drag_event_monitor) {
- bridge->WaitForShouldRepost();
- EXPECT_TRUE(bridge->did_repost());
- EXPECT_TRUE(bridge->IsDraggable());
- bridge->WaitForShouldRepost();
- EXPECT_FALSE(bridge->did_repost());
- EXPECT_FALSE(bridge->IsDraggable());
- } else {
- WaitForEvent(NSLeftMouseDownMask);
- }
+ WaitForEvent(NSLeftMouseDownMask);
base::scoped_nsobject<WindowedNSNotificationObserver> did_move_observer(
[[WindowedNSNotificationObserver alloc]
@@ -449,7 +385,6 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
initForNotification:NSWindowWillMoveNotification]);
NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
bottom_right_point, window);
- EXPECT_FALSE(bridge->IsDraggable());
CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
base::scoped_nsobject<WindowedNSNotificationObserver> did_resize_observer(
@@ -463,14 +398,6 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
NSMakePoint(x + 408, y + 2), NSLeftMouseUp, 0);
CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
- if (using_drag_event_monitor) {
- // The only event observed by us is the original mouse-down. It should not
- // be reposted.
- bridge->WaitForShouldRepost();
- EXPECT_FALSE(bridge->did_repost());
- EXPECT_FALSE(bridge->IsDraggable());
- }
-
EXPECT_TRUE([did_resize_observer wait]);
EXPECT_EQ(0, [will_move_observer notificationCount]);
EXPECT_EQ(410, [window frame].size.width);
diff --git a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
index a61d582b79c..0f44dc785d3 100644
--- a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
@@ -122,27 +122,6 @@
if ([commandDispatcher_ preSendEvent:event])
return;
- // If a window drag event monitor is not used, query the BridgedNativeWidget
- // to decide if a window drag should be performed.
- // This conditional is equivalent to
- // !views::BridgedNativeWidget::ShouldUseDragEventMonitor(), but it also
- // supresses the -Wunguarded-availability warning.
- if (@available(macOS 10.11, *)) {
- views::BridgedNativeWidget* bridge =
- views::NativeWidgetMac::GetBridgeForNativeWindow(self);
-
- if (bridge && bridge->ShouldDragWindow(event)) {
- // Using performWindowDragWithEvent: does not generate a
- // NSWindowWillMoveNotification. Hence post one.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:NSWindowWillMoveNotification
- object:self];
-
- [self performWindowDragWithEvent:event];
- return;
- }
- }
-
NSEventType type = [event type];
if ((type != NSKeyDown && type != NSKeyUp) || ![self hasViewsMenuActive]) {
[super sendEvent:event];
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index f082282683b..d844b6a58f2 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -388,7 +388,7 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener,
layout->StartRow(0, 0);
textfield_ = new Textfield();
textfield_->set_controller(this);
- textfield_->set_default_width_in_chars(kTextfieldLengthInChars);
+ textfield_->SetDefaultWidthInChars(kTextfieldLengthInChars);
layout->AddView(textfield_);
selected_color_patch_ = new SelectedColorPatchView();
layout->AddView(selected_color_patch_);
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index 77c453f79d0..8a2e4dff278 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -444,6 +444,7 @@ void Button::OnBlur() {
std::unique_ptr<InkDrop> Button::CreateInkDrop() {
std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
ink_drop->SetShowHighlightOnFocus(true);
+ ink_drop->SetAutoHighlightModeForPlatform();
return std::move(ink_drop);
}
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 8468460448f..ecdcda3d503 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -16,6 +16,7 @@
#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/button/label_button_border.h"
@@ -76,6 +77,7 @@ const char Checkbox::kViewClassName[] = "Checkbox";
Checkbox::Checkbox(const base::string16& label, bool force_md)
: LabelButton(NULL, label),
checked_(false),
+ label_ax_id_(0),
use_md_(force_md ||
ui::MaterialDesignController::IsSecondaryUiMaterial()) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -152,6 +154,18 @@ void Checkbox::SetMultiLine(bool multi_line) {
label()->SetMultiLine(multi_line);
}
+void Checkbox::SetAssociatedLabel(View* labelling_view) {
+ DCHECK(labelling_view);
+ label_ax_id_ = labelling_view->GetViewAccessibility().GetUniqueId().Get();
+ ui::AXNodeData node_data;
+ labelling_view->GetAccessibleNodeData(&node_data);
+ // TODO(aleventhal) automatically handle setting the name from the related
+ // label in view_accessibility and have it update the name if the text of the
+ // associated label changes.
+ SetAccessibleName(
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+}
+
// TODO(tetsui): Remove this method and |use_md_| when MD for secondary UI
// becomes default and IsSecondaryUiMaterial() is tautology.
bool Checkbox::UseMd() const {
@@ -176,6 +190,10 @@ void Checkbox::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kCheck);
}
}
+ if (label_ax_id_) {
+ node_data->AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
+ {label_ax_id_});
+ }
}
void Checkbox::OnFocus() {
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index f6605e8dd4c..ca8da3cb2af 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -39,6 +39,15 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
void SetMultiLine(bool multi_line);
+ // If the accessible name should be the same as the labelling view's text,
+ // use this. It will set the accessible label relationship and copy the
+ // accessible name from the labelling views's accessible name. Any view with
+ // an accessible name can be used, e.g. a Label, StyledLabel or Link.
+ void SetAssociatedLabel(View* labelling_view);
+
+ // LabelButton:
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
protected:
// Returns whether MD is enabled. Returns true if |force_md| in the
// constructor or --secondary-ui-md flag is set.
@@ -46,7 +55,6 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// LabelButton:
const char* GetClassName() const override;
- void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void OnFocus() override;
void OnBlur() override;
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
@@ -95,6 +103,9 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// The images for each button node_data.
gfx::ImageSkia images_[2][2][STATE_COUNT];
+ // The unique id for the associated label's accessible object.
+ int32_t label_ax_id_;
+
bool use_md_;
DISALLOW_COPY_AND_ASSIGN(Checkbox);
diff --git a/chromium/ui/views/controls/button/checkbox_unittest.cc b/chromium/ui/views/controls/button/checkbox_unittest.cc
new file mode 100644
index 00000000000..2984921c5ff
--- /dev/null
+++ b/chromium/ui/views/controls/button/checkbox_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/button/checkbox.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/styled_label.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace views {
+
+class CheckboxTest : public ViewsTestBase {
+ public:
+ CheckboxTest() {}
+ ~CheckboxTest() override {}
+
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+
+ // Create a widget so that the Checkbox can query the hover state
+ // correctly.
+ widget_ = std::make_unique<Widget>();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 650, 650);
+ widget_->Init(params);
+ widget_->Show();
+
+ checkbox_ = new Checkbox(base::string16());
+ widget_->SetContentsView(checkbox_);
+ }
+
+ void TearDown() override {
+ widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ protected:
+ Checkbox* checkbox() { return checkbox_; }
+
+ private:
+ std::unique_ptr<Widget> widget_;
+ Checkbox* checkbox_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(CheckboxTest);
+};
+
+TEST_F(CheckboxTest, AccessibilityTest) {
+ const base::string16 label_text = base::ASCIIToUTF16("Some label");
+ StyledLabel label(label_text, nullptr);
+ checkbox()->SetAssociatedLabel(&label);
+
+ ui::AXNodeData ax_data;
+ checkbox()->GetAccessibleNodeData(&ax_data);
+
+ EXPECT_EQ(ax_data.GetString16Attribute(ax::mojom::StringAttribute::kName),
+ label_text);
+ EXPECT_EQ(ax_data.role, ax::mojom::Role::kCheckBox);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/image_button_factory.cc b/chromium/ui/views/controls/button/image_button_factory.cc
index 6e7ddda2763..649002d85ad 100644
--- a/chromium/ui/views/controls/button/image_button_factory.cc
+++ b/chromium/ui/views/controls/button/image_button_factory.cc
@@ -1,7 +1,6 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/gfx/color_utils.h"
diff --git a/chromium/ui/views/controls/button/image_button_factory.h b/chromium/ui/views/controls/button/image_button_factory.h
index d9659570d0a..2bb9a229bd4 100644
--- a/chromium/ui/views/controls/button/image_button_factory.h
+++ b/chromium/ui/views/controls/button/image_button_factory.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_FACTORY_H_
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_palette.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -28,7 +29,7 @@ VIEWS_EXPORT ImageButton* CreateVectorImageButton(ButtonListener* listener);
VIEWS_EXPORT void SetImageFromVectorIcon(
ImageButton* button,
const gfx::VectorIcon& icon,
- SkColor related_text_color = SK_ColorBLACK);
+ SkColor related_text_color = gfx::kGoogleGrey900);
} // namespace views
diff --git a/chromium/ui/views/controls/button/image_button_factory_unittest.cc b/chromium/ui/views/controls/button/image_button_factory_unittest.cc
index c23149989a3..52728ff3516 100644
--- a/chromium/ui/views/controls/button/image_button_factory_unittest.cc
+++ b/chromium/ui/views/controls/button/image_button_factory_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/button/image_button_factory.h"
#include "components/vector_icons/vector_icons.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/animation/test/ink_drop_host_view_test_api.h"
#include "ui/views/controls/button/button.h"
@@ -31,9 +32,9 @@ TEST_F(ImageButtonFactoryTest, SetImageFromVectorIcon) {
EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorRED),
button->GetInkDropBaseColor());
- // Default to black.
+ // Default to GoogleGrey900.
SetImageFromVectorIcon(button, vector_icons::kClose16Icon);
- EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorBLACK),
+ EXPECT_EQ(color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey900),
button->GetInkDropBaseColor());
delete button;
}
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 7cf98686b71..d56f4cb2f73 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -10,7 +10,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index d79d8a473b0..7908d16fc50 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -15,6 +15,7 @@
#include "ui/native_theme/native_theme.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/layout/layout_provider.h"
#include "ui/views/native_theme_delegate.h"
#include "ui/views/resources/grit/views_resources.h"
@@ -113,7 +114,8 @@ gfx::Insets LabelButtonAssetBorder::GetDefaultInsetsForStyle(
if (style == Button::STYLE_BUTTON) {
insets = gfx::Insets(8, 13);
} else if (style == Button::STYLE_TEXTBUTTON) {
- insets = gfx::Insets(5, 6);
+ insets = LayoutProvider::Get()->GetInsetsMetric(
+ InsetsMetric::INSETS_LABEL_BUTTON);
} else {
NOTREACHED();
}
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index b708b83b434..60f6ca0ffb3 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -159,7 +159,7 @@ std::unique_ptr<views::InkDropHighlight> MdTextButton::CreateInkDropHighlight()
return std::make_unique<InkDropHighlight>(
gfx::RectF(GetLocalBounds()).CenterPoint(),
base::WrapUnique(new BorderShadowLayerDelegate(
- shadows, GetLocalBounds(), fill_color, kInkDropSmallCornerRadius)));
+ shadows, GetLocalBounds(), fill_color, corner_radius_)));
}
void MdTextButton::SetEnabledTextColors(SkColor color) {
@@ -179,7 +179,8 @@ void MdTextButton::UpdateStyleToIndicateDefaultStatus() {
MdTextButton::MdTextButton(ButtonListener* listener, int button_context)
: LabelButton(listener, base::string16(), button_context),
- is_prominent_(false) {
+ is_prominent_(false),
+ corner_radius_(kInkDropSmallCornerRadius) {
SetInkDropMode(InkDropMode::ON);
set_has_ink_drop_action_on_click(true);
SetHorizontalAlignment(gfx::ALIGN_CENTER);
@@ -330,7 +331,7 @@ void MdTextButton::UpdateColors() {
DCHECK_EQ(SK_AlphaOPAQUE, static_cast<int>(SkColorGetA(bg_color)));
SetBackground(
CreateBackgroundFromPainter(Painter::CreateRoundRectWith1PxBorderPainter(
- bg_color, stroke_color, kInkDropSmallCornerRadius)));
+ bg_color, stroke_color, corner_radius_)));
SchedulePaint();
}
diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h
index 27ba3c0cb97..25f65ce5e87 100644
--- a/chromium/ui/views/controls/button/md_text_button.h
+++ b/chromium/ui/views/controls/button/md_text_button.h
@@ -34,6 +34,10 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
// See |bg_color_override_|.
void SetBgColorOverride(const base::Optional<SkColor>& color);
+ // Override the default corner radius of the round rect used for the
+ // background and ink drop effects.
+ void set_corner_radius(float radius) { corner_radius_ = radius; }
+
// View:
void OnPaintBackground(gfx::Canvas* canvas) override;
@@ -64,6 +68,8 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
// When set, this provides the background color.
base::Optional<SkColor> bg_color_override_;
+ float corner_radius_;
+
DISALLOW_COPY_AND_ASSIGN(MdTextButton);
};
diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc
index 4a898face54..e12bae6e2d9 100644
--- a/chromium/ui/views/controls/button/menu_button_unittest.cc
+++ b/chromium/ui/views/controls/button/menu_button_unittest.cc
@@ -579,7 +579,8 @@ TEST_F(MenuButtonTest, DraggableMenuButtonDoesNotActivateOnDrag) {
TestDragDropClient drag_client;
SetDragDropClient(GetContext(), &drag_client);
- button()->PrependPreTargetHandler(&drag_client);
+ button()->AddPreTargetHandler(&drag_client,
+ ui::EventTarget::Priority::kSystem);
generator()->DragMouseBy(10, 0);
EXPECT_EQ(nullptr, menu_button_listener.last_source());
diff --git a/chromium/ui/views/controls/button/toggle_button_unittest.cc b/chromium/ui/views/controls/button/toggle_button_unittest.cc
index ac6191418b0..2315f7935b7 100644
--- a/chromium/ui/views/controls/button/toggle_button_unittest.cc
+++ b/chromium/ui/views/controls/button/toggle_button_unittest.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/button/toggle_button.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_utils.h"
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
index a5a44bac724..1cf8348a308 100644
--- a/chromium/ui/views/controls/focus_ring.cc
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -5,21 +5,14 @@
#include "ui/views/controls/focus_ring.h"
#include "ui/gfx/canvas.h"
-#include "ui/views/controls/focusable_border.h"
namespace views {
namespace {
-// The stroke width of the focus border in dp.
+// The default stroke width of the focus border in dp.
constexpr float kFocusHaloThicknessDp = 2.f;
-// The focus indicator should hug the normal border, when present (as in the
-// case of text buttons). Since it's drawn outside the parent view, we have to
-// increase the rounding slightly.
-constexpr float kFocusHaloCornerRadiusDp =
- FocusableBorder::kCornerRadiusDp + kFocusHaloThicknessDp / 2.f;
-
FocusRing* GetFocusRing(View* parent) {
for (int i = 0; i < parent->child_count(); ++i) {
if (parent->child_at(i)->GetClassName() == FocusRing::kViewClassName)
@@ -33,20 +26,38 @@ FocusRing* GetFocusRing(View* parent) {
const char FocusRing::kViewClassName[] = "FocusRing";
// static
-views::View* FocusRing::Install(View* parent,
- ui::NativeTheme::ColorId override_color_id) {
+FocusRing* FocusRing::Install(View* parent,
+ SkColor color,
+ float corner_radius) {
FocusRing* ring = GetFocusRing(parent);
if (!ring) {
- ring = new FocusRing();
+ ring = new FocusRing(color, corner_radius);
parent->AddChildView(ring);
+ } else {
+ ring->color_ = color;
+ ring->corner_radius_ = corner_radius;
}
- ring->override_color_id_ = override_color_id;
ring->Layout();
ring->SchedulePaint();
return ring;
}
// static
+FocusRing* FocusRing::Install(View* parent,
+ ui::NativeTheme::ColorId override_color_id) {
+ SkColor ring_color = parent->GetNativeTheme()->GetSystemColor(
+ override_color_id == ui::NativeTheme::kColorId_NumColors
+ ? ui::NativeTheme::kColorId_FocusedBorderColor
+ : override_color_id);
+ FocusRing* ring = Install(parent, ring_color);
+ DCHECK(ring);
+ ring->override_color_id_ = override_color_id;
+ if (!ring->view_observer_.IsObserving(parent))
+ ring->view_observer_.Add(parent);
+ return ring;
+}
+
+// static
void FocusRing::Uninstall(View* parent) {
delete GetFocusRing(parent);
}
@@ -75,21 +86,27 @@ void FocusRing::Layout() {
void FocusRing::OnPaint(gfx::Canvas* canvas) {
cc::PaintFlags flags;
flags.setAntiAlias(true);
- flags.setColor(
- SkColorSetA(GetNativeTheme()->GetSystemColor(
- override_color_id_ != ui::NativeTheme::kColorId_NumColors
- ? override_color_id_
- : ui::NativeTheme::kColorId_FocusedBorderColor),
- 0x66));
+ flags.setColor(SkColorSetA(color_, 0x66));
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setStrokeWidth(kFocusHaloThicknessDp);
gfx::RectF rect(GetLocalBounds());
rect.Inset(gfx::InsetsF(kFocusHaloThicknessDp / 2.f));
- canvas->DrawRoundRect(rect, kFocusHaloCornerRadiusDp, flags);
+ // The focus indicator should hug the normal border, when present (as in the
+ // case of text buttons). Since it's drawn outside the parent view, increase
+ // the rounding slightly by adding half the ring thickness.
+ canvas->DrawRoundRect(rect, corner_radius_ + kFocusHaloThicknessDp / 2.f,
+ flags);
+}
+
+void FocusRing::OnViewNativeThemeChanged(View* observed_view) {
+ if (override_color_id_) {
+ color_ = observed_view->GetNativeTheme()->GetSystemColor(
+ override_color_id_.value());
+ }
}
-FocusRing::FocusRing()
- : override_color_id_(ui::NativeTheme::kColorId_NumColors) {
+FocusRing::FocusRing(SkColor color, float corner_radius)
+ : color_(color), corner_radius_(corner_radius), view_observer_(this) {
InitFocusRing(this);
}
diff --git a/chromium/ui/views/controls/focus_ring.h b/chromium/ui/views/controls/focus_ring.h
index f6ecc2a9e78..df1f1b330ca 100644
--- a/chromium/ui/views/controls/focus_ring.h
+++ b/chromium/ui/views/controls/focus_ring.h
@@ -5,24 +5,37 @@
#ifndef UI_VIEWS_CONTROLS_FOCUS_RING_H_
#define UI_VIEWS_CONTROLS_FOCUS_RING_H_
+#include "base/scoped_observer.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/controls/focusable_border.h"
#include "ui/views/view.h"
+#include "ui/views/view_observer.h"
+#include "ui/views/views_export.h"
namespace views {
// FocusRing is a View that is designed to act as an indicator of focus for its
// parent. It is a stand-alone view that paints to a layer which extends beyond
// the bounds of its parent view.
-class FocusRing : public View {
+class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
public:
static const char kViewClassName[];
// Create a FocusRing and adds it to |parent|, or updates the one that already
- // exists. |override_color_id| will be used in place of the default coloration
+ // exists with the given |color| and |corner_radius|.
+ // TODO(crbug.com/831926): Prefer using the below Install() method - this one
+ // should eventually be removed.
+ static FocusRing* Install(
+ View* parent,
+ SkColor color,
+ float corner_radius = FocusableBorder::kCornerRadiusDp);
+
+ // Similar to FocusRing::Install(View, SkColor, float), but
+ // |override_color_id| will be used in place of the default coloration
// when provided.
- static View* Install(View* parent,
- ui::NativeTheme::ColorId override_color_id =
- ui::NativeTheme::kColorId_NumColors);
+ static FocusRing* Install(View* parent,
+ ui::NativeTheme::ColorId override_color_id =
+ ui::NativeTheme::kColorId_NumColors);
// Removes the FocusRing from |parent|.
static void Uninstall(View* parent);
@@ -35,12 +48,18 @@ class FocusRing : public View {
void Layout() override;
void OnPaint(gfx::Canvas* canvas) override;
+ // ViewObserver:
+ void OnViewNativeThemeChanged(View* observed_view) override;
+
protected:
- FocusRing();
+ FocusRing(SkColor color, float corner_radius);
~FocusRing() override;
private:
- ui::NativeTheme::ColorId override_color_id_;
+ SkColor color_;
+ float corner_radius_;
+ base::Optional<ui::NativeTheme::ColorId> override_color_id_;
+ ScopedObserver<View, FocusRing> view_observer_;
DISALLOW_COPY_AND_ASSIGN(FocusRing);
};
diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc
index badae559e96..059a83652f7 100644
--- a/chromium/ui/views/controls/image_view.cc
+++ b/chromium/ui/views/controls/image_view.cc
@@ -29,8 +29,7 @@ void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
const char ImageView::kViewClassName[] = "ImageView";
ImageView::ImageView()
- : image_size_set_(false),
- horiz_alignment_(CENTER),
+ : horiz_alignment_(CENTER),
vert_alignment_(CENTER),
last_paint_scale_(0.f),
last_painted_bitmap_pixels_(NULL) {}
@@ -63,7 +62,6 @@ const gfx::ImageSkia& ImageView::GetImage() const {
}
void ImageView::SetImageSize(const gfx::Size& image_size) {
- image_size_set_ = true;
image_size_ = image_size;
PreferredSizeChanged();
}
@@ -74,7 +72,7 @@ gfx::Rect ImageView::GetImageBounds() const {
}
void ImageView::ResetImageSize() {
- image_size_set_ = false;
+ image_size_.reset();
}
bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
@@ -89,7 +87,7 @@ bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
}
gfx::Size ImageView::GetImageSize() const {
- return image_size_set_ ? image_size_ : image_.size();
+ return image_size_.value_or(image_.size());
}
gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h
index 751bee97277..178c50e5087 100644
--- a/chromium/ui/views/controls/image_view.h
+++ b/chromium/ui/views/controls/image_view.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_CONTROLS_IMAGE_VIEW_H_
#include "base/macros.h"
+#include "base/optional.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/view.h"
@@ -98,11 +99,8 @@ class VIEWS_EXPORT ImageView : public View {
// properties.
gfx::Point ComputeImageOrigin(const gfx::Size& image_size) const;
- // Whether the image size is set.
- bool image_size_set_;
-
// The actual image size.
- gfx::Size image_size_;
+ base::Optional<gfx::Size> image_size_;
// The underlying image.
gfx::ImageSkia image_;
diff --git a/chromium/ui/views/controls/image_view_unittest.cc b/chromium/ui/views/controls/image_view_unittest.cc
index 417d342d445..28cbb21460a 100644
--- a/chromium/ui/views/controls/image_view_unittest.cc
+++ b/chromium/ui/views/controls/image_view_unittest.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/image_view.h"
#include "base/i18n/rtl.h"
-#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index 6b6d5f02b8a..b5baab3cbb1 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -14,7 +14,6 @@
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_node_data.h"
@@ -665,13 +664,21 @@ void Label::ShowContextMenuForView(View* source,
MENU_ANCHOR_TOPLEFT, source_type);
}
-bool Label::GetDecoratedWordAtPoint(const gfx::Point& point,
- gfx::DecoratedText* decorated_word,
- gfx::Point* baseline_point) {
+bool Label::GetWordLookupDataAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) {
+ gfx::RenderText* render_text = GetRenderTextForSelectionController();
+ return render_text ? render_text->GetWordLookupDataAtPoint(
+ point, decorated_word, baseline_point)
+ : false;
+}
+
+bool Label::GetWordLookupDataFromSelection(gfx::DecoratedText* decorated_text,
+ gfx::Point* baseline_point) {
gfx::RenderText* render_text = GetRenderTextForSelectionController();
return render_text
- ? render_text->GetDecoratedWordAtPoint(point, decorated_word,
- baseline_point)
+ ? render_text->GetLookupDataForRange(
+ render_text->selection(), decorated_text, baseline_point)
: false;
}
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 635025a8250..1d35afeda78 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -268,9 +268,12 @@ class VIEWS_EXPORT Label : public View,
ui::MenuSourceType source_type) override;
// WordLookupClient overrides:
- bool GetDecoratedWordAtPoint(const gfx::Point& point,
- gfx::DecoratedText* decorated_word,
- gfx::Point* baseline_point) override;
+ bool GetWordLookupDataAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) override;
+
+ bool GetWordLookupDataFromSelection(gfx::DecoratedText* decorated_text,
+ gfx::Point* baseline_point) override;
// SelectionControllerDelegate overrides:
gfx::RenderText* GetRenderTextForSelectionController() override;
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index 54654acf866..ec25ede20df 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -8,7 +8,6 @@
#include "base/command_line.h"
#include "base/i18n/rtl.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
@@ -190,10 +189,10 @@ class LabelSelectionTest : public LabelTest {
return widget()->GetFocusManager()->GetFocusedView();
}
- void PerformMousePress(const gfx::Point& point, int extra_flags = 0) {
+ void PerformMousePress(const gfx::Point& point) {
ui::MouseEvent pressed_event = ui::MouseEvent(
ui::ET_MOUSE_PRESSED, point, point, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON | extra_flags);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
label()->OnMousePressed(pressed_event);
}
@@ -204,8 +203,8 @@ class LabelSelectionTest : public LabelTest {
label()->OnMouseReleased(released_event);
}
- void PerformClick(const gfx::Point& point, int extra_flags = 0) {
- PerformMousePress(point, extra_flags);
+ void PerformClick(const gfx::Point& point) {
+ PerformMousePress(point);
PerformMouseRelease(point);
}
@@ -1088,7 +1087,7 @@ TEST_F(LabelSelectionTest, DoubleTripleClick) {
EXPECT_TRUE(GetSelectedText().empty());
// Double clicking should select the word under cursor.
- PerformClick(GetCursorPoint(0), ui::EF_IS_DOUBLE_CLICK);
+ PerformClick(GetCursorPoint(0));
EXPECT_STR_EQ("Label", GetSelectedText());
// Triple clicking should select all the text.
@@ -1102,7 +1101,7 @@ TEST_F(LabelSelectionTest, DoubleTripleClick) {
// Clicking at another location should clear the selection.
PerformClick(GetCursorPoint(8));
EXPECT_TRUE(GetSelectedText().empty());
- PerformClick(GetCursorPoint(8), ui::EF_IS_DOUBLE_CLICK);
+ PerformClick(GetCursorPoint(8));
EXPECT_STR_EQ("double", GetSelectedText());
}
@@ -1298,7 +1297,7 @@ TEST_F(LabelSelectionTest, MouseDragWord) {
ASSERT_TRUE(label()->SetSelectable(true));
PerformClick(GetCursorPoint(8));
- PerformMousePress(GetCursorPoint(8), ui::EF_IS_DOUBLE_CLICK);
+ PerformMousePress(GetCursorPoint(8));
EXPECT_STR_EQ("drag", GetSelectedText());
PerformMouseDragTo(GetCursorPoint(0));
diff --git a/chromium/ui/views/controls/menu/menu_closure_animation_mac.h b/chromium/ui/views/controls/menu/menu_closure_animation_mac.h
new file mode 100644
index 00000000000..5c3b6d69aff
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.h
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_CLOSURE_ANIMATION_MAC_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_CLOSURE_ANIMATION_MAC_H_
+
+#include "base/macros.h"
+#include "base/timer/timer.h"
+#include "ui/gfx/animation/animation.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class MenuItemView;
+
+// This class implements the Mac menu closure animation:
+// 1) For 100ms, the selected item is drawn as unselected
+// 2) Then, for another 100ms, the selected item is drawn as selected
+// 3) Then, and the window fades over 250ms to transparency
+// Note that this class is owned by the involved MenuController, so if the menu
+// is destructed early for any reason, this class will be destructed also, which
+// will stop the timer or animation (if they are running), so the callback will
+// *not* be run - which is good, since the MenuController that would have
+// received it is being deleted.
+class VIEWS_EXPORT MenuClosureAnimationMac : public gfx::AnimationDelegate {
+ public:
+ // After this closure animation is done, |callback| is run to finally accept
+ // |item|.
+ MenuClosureAnimationMac(MenuItemView* item, base::OnceClosure callback);
+ ~MenuClosureAnimationMac() override;
+
+ // Start the animation.
+ void Start();
+
+ // Returns the MenuItemView this animation targets.
+ MenuItemView* item() { return item_; }
+
+ // Causes animations to take no time for testing purposes. Note that this
+ // still causes the completion callback to be run asynchronously, so test
+ // situations have the same control flow as non-test situations.
+ static void DisableAnimationsForTesting();
+
+ private:
+ enum class AnimationStep {
+ kStart,
+ kUnselected,
+ kSelected,
+ kFading,
+ kFinish,
+ };
+
+ static constexpr AnimationStep NextStepFor(AnimationStep step);
+
+ void AdvanceAnimation();
+
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
+ void AnimationCanceled(const gfx::Animation* animation) override;
+
+ base::OnceClosure callback_;
+ base::OneShotTimer timer_;
+ std::unique_ptr<gfx::Animation> fade_animation_;
+ MenuItemView* item_;
+ AnimationStep step_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuClosureAnimationMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_CLOSURE_ANIMATION_MAC_H_
diff --git a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
new file mode 100644
index 00000000000..2bec6d31087
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_closure_animation_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gfx/animation/linear_animation.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+static bool g_disable_animations_for_testing = false;
+}
+
+namespace views {
+
+MenuClosureAnimationMac::MenuClosureAnimationMac(MenuItemView* item,
+ base::OnceClosure callback)
+ : callback_(std::move(callback)),
+ item_(item),
+ step_(AnimationStep::kStart) {}
+
+MenuClosureAnimationMac::~MenuClosureAnimationMac() {}
+
+void MenuClosureAnimationMac::Start() {
+ DCHECK_EQ(step_, AnimationStep::kStart);
+ if (g_disable_animations_for_testing) {
+ // Even when disabling animations, simulate the fact that the eventual
+ // accept callback will happen after a runloop cycle by skipping to the end
+ // of the animation.
+ step_ = AnimationStep::kFading;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&MenuClosureAnimationMac::AdvanceAnimation,
+ base::Unretained(this)));
+ return;
+ }
+ AdvanceAnimation();
+}
+
+// static
+constexpr MenuClosureAnimationMac::AnimationStep
+MenuClosureAnimationMac::NextStepFor(
+ MenuClosureAnimationMac::AnimationStep step) {
+ switch (step) {
+ case AnimationStep::kStart:
+ return AnimationStep::kUnselected;
+ case AnimationStep::kUnselected:
+ return AnimationStep::kSelected;
+ case AnimationStep::kSelected:
+ return AnimationStep::kFading;
+ case AnimationStep::kFading:
+ return AnimationStep::kFinish;
+ case AnimationStep::kFinish:
+ return AnimationStep::kFinish;
+ }
+}
+
+void MenuClosureAnimationMac::AdvanceAnimation() {
+ step_ = NextStepFor(step_);
+ if (step_ == AnimationStep::kUnselected ||
+ step_ == AnimationStep::kSelected) {
+ item_->SetForcedVisualSelection(step_ == AnimationStep::kSelected);
+ timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(80),
+ base::BindRepeating(&MenuClosureAnimationMac::AdvanceAnimation,
+ base::Unretained(this)));
+ } else if (step_ == AnimationStep::kFading) {
+ auto fade = std::make_unique<gfx::LinearAnimation>(this);
+ fade->SetDuration(base::TimeDelta::FromMilliseconds(200));
+ fade_animation_ = std::move(fade);
+ fade_animation_->Start();
+ } else if (step_ == AnimationStep::kFinish) {
+ std::move(callback_).Run();
+ }
+}
+
+// static
+void MenuClosureAnimationMac::DisableAnimationsForTesting() {
+ g_disable_animations_for_testing = true;
+}
+
+void MenuClosureAnimationMac::AnimationProgressed(
+ const gfx::Animation* animation) {
+ NSWindow* window = item_->GetWidget()->GetNativeWindow();
+ [window setAlphaValue:animation->CurrentValueBetween(1.0, 0.0)];
+}
+
+void MenuClosureAnimationMac::AnimationEnded(const gfx::Animation* animation) {
+ AdvanceAnimation();
+}
+
+void MenuClosureAnimationMac::AnimationCanceled(
+ const gfx::Animation* animation) {
+ NOTREACHED();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 001179c5198..62fbbca1d1d 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "ui/views/controls/menu/menu_image_util.h"
#include "ui/views/round_rect_painter.h"
-
namespace views {
MenuConfig::MenuConfig()
@@ -19,10 +18,16 @@ MenuConfig::MenuConfig()
item_bottom_margin(3),
item_no_icon_top_margin(4),
item_no_icon_bottom_margin(4),
+ fixed_text_item_height(0),
+ fixed_menu_width(0),
item_left_margin(10),
+ touchable_item_left_margin(16),
label_to_arrow_padding(10),
arrow_to_edge_padding(5),
icon_to_label_padding(10),
+ touchable_icon_to_label_padding(22),
+ touchable_icon_size(20),
+ touchable_icon_color(SkColorSetA(SK_ColorBLACK, 0xDE)),
check_width(kMenuCheckSize),
check_height(kMenuCheckSize),
arrow_width(kSubmenuArrowSize),
@@ -43,7 +48,13 @@ MenuConfig::MenuConfig()
icons_in_label(false),
check_selected_combobox_item(false),
show_delay(400),
- corner_radius(0) {
+ corner_radius(0),
+ touchable_corner_radius(8),
+ touchable_anchor_offset(8),
+ touchable_menu_height(36),
+ touchable_menu_width(256),
+ touchable_menu_shadow_elevation(12),
+ vertical_touchable_menu_item_padding(8) {
Init();
}
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index a4ecc47839b..3fbb794646a 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -44,9 +44,19 @@ struct VIEWS_EXPORT MenuConfig {
int item_no_icon_top_margin;
int item_no_icon_bottom_margin;
+ // Fixed dimensions used for entire items. If these are nonzero, they override
+ // the vertical margin constants given above - the item's text and icon are
+ // vertically centered within these heights.
+ int fixed_text_item_height;
+ int fixed_container_item_height;
+ int fixed_menu_width;
+
// Margins between the left of the item and the icon.
int item_left_margin;
+ // Margins between the left of the touchable item and the icon.
+ int touchable_item_left_margin;
+
// Padding between the label and submenu arrow.
int label_to_arrow_padding;
@@ -56,6 +66,15 @@ struct VIEWS_EXPORT MenuConfig {
// Padding between the icon and label.
int icon_to_label_padding;
+ // Padding between the icon and label for touchable menu items.
+ int touchable_icon_to_label_padding;
+
+ // The icon size used for icons in touchable menu items.
+ int touchable_icon_size;
+
+ // The color used for icons in touchable menu items.
+ SkColor touchable_icon_color;
+
// The space reserved for the check. The actual size of the image may be
// different.
int check_width;
@@ -121,6 +140,24 @@ struct VIEWS_EXPORT MenuConfig {
// Radius of the rounded corners of the menu border. Must be >= 0.
int corner_radius;
+ // Radius of the rounded corners of the touchable menu border
+ int touchable_corner_radius;
+
+ // Anchor offset for touchable menus created by a touch event.
+ int touchable_anchor_offset;
+
+ // Height of child MenuItemViews for touchable menus.
+ int touchable_menu_height;
+
+ // Width of touchable menus.
+ int touchable_menu_width;
+
+ // Shadow elevation of touchable menus.
+ int touchable_menu_shadow_elevation;
+
+ // Vertical padding for touchable menus.
+ int vertical_touchable_menu_item_padding;
+
private:
// Configures a MenuConfig as appropriate for the current platform.
void Init();
diff --git a/chromium/ui/views/controls/menu/menu_config_mac.mm b/chromium/ui/views/controls/menu/menu_config_mac.mm
index fc66f894436..e950582f43f 100644
--- a/chromium/ui/views/controls/menu/menu_config_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_config_mac.mm
@@ -7,37 +7,44 @@
#import <AppKit/AppKit.h>
#include "base/mac/mac_util.h"
-
-namespace views {
+#include "ui/base/material_design/material_design_controller.h"
namespace {
-// The height of the menu separator in pixels.
-const int kMenuSeparatorHeight = 2;
-const int kMenuSeparatorHeightMavericks = 1;
+void InitMaterialMenuConfig(views::MenuConfig* config) {
+ // These config parameters are from https://crbug.com/829347 and the spec
+ // images linked from that bug.
+ config->menu_vertical_border_size = 8;
+ config->menu_horizontal_border_size = 0;
+ config->submenu_horizontal_inset = 0;
+ config->fixed_text_item_height = 32;
+ config->fixed_container_item_height = 48;
+ config->fixed_menu_width = 320;
+ config->item_left_margin = 8;
+ config->label_to_arrow_padding = 0;
+ config->arrow_to_edge_padding = 16;
+ config->icon_to_label_padding = 8;
+ config->check_width = 16;
+ config->check_height = 16;
+ config->arrow_width = 8;
+ config->separator_height = 17;
+ config->separator_thickness = 1;
+ config->label_to_minor_text_padding = 8;
+ config->align_arrow_and_shortcut = true;
+ config->use_outer_border = false;
+ config->icons_in_label = true;
+ config->corner_radius = 8;
+}
} // namespace
+namespace views {
+
void MenuConfig::Init() {
font_list = gfx::FontList(gfx::Font([NSFont menuFontOfSize:0.0]));
- menu_vertical_border_size = 4;
- item_top_margin = item_no_icon_top_margin = 1;
- item_bottom_margin = item_no_icon_bottom_margin = 1;
- item_left_margin = 2;
- arrow_to_edge_padding = 13;
- icon_to_label_padding = 4;
- check_width = 19;
- check_height = 11;
- separator_height = 13;
- separator_upper_height = 7;
- separator_lower_height = 6;
- separator_thickness = base::mac::IsOS10_9() ? kMenuSeparatorHeightMavericks
- : kMenuSeparatorHeight;
- align_arrow_and_shortcut = true;
- icons_in_label = true;
check_selected_combobox_item = true;
- corner_radius = 5;
- use_outer_border = false;
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial())
+ InitMaterialMenuConfig(this);
}
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 4feb2cd4b2e..46713d7170a 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -4,10 +4,12 @@
#include "ui/views/controls/menu/menu_controller.h"
+#include <algorithm>
+#include <utility>
+
#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -164,7 +166,7 @@ View* GetNextFocusableView(View* ancestor, View* start_at, bool forward) {
}
#if defined(OS_WIN) || defined(OS_CHROMEOS)
-// Determines the correct cooridinates and window to repost |event| to, if it is
+// Determines the correct coordinates and window to repost |event| to, if it is
// a mouse or touch event.
static void RepostEventImpl(const ui::LocatedEvent* event,
const gfx::Point& screen_loc,
@@ -1145,6 +1147,13 @@ void MenuController::TurnOffMenuSelectionHoldForTest() {
menu_selection_hold_time_ms = -1;
}
+void MenuController::OnMenuItemDestroying(MenuItemView* menu_item) {
+#if defined(OS_MACOSX)
+ if (menu_closure_animation_ && menu_closure_animation_->item() == menu_item)
+ menu_closure_animation_.reset();
+#endif
+}
+
void MenuController::SetSelection(MenuItemView* menu_item,
int selection_types) {
size_t paths_differ_at = 0;
@@ -1470,8 +1479,25 @@ void MenuController::UpdateInitialLocation(const gfx::Rect& bounds,
}
void MenuController::Accept(MenuItemView* item, int event_flags) {
+#if defined(OS_MACOSX)
+ menu_closure_animation_ = std::make_unique<MenuClosureAnimationMac>(
+ item,
+ base::BindOnce(&MenuController::ReallyAccept, base::Unretained(this),
+ base::Unretained(item), event_flags));
+ menu_closure_animation_->Start();
+#else
+ ReallyAccept(item, event_flags);
+#endif
+}
+
+void MenuController::ReallyAccept(MenuItemView* item, int event_flags) {
DCHECK(IsBlockingRun());
result_ = item;
+#if defined(OS_MACOSX)
+ // Reset the closure animation since it's now finished - this also unblocks
+ // input events for the menu.
+ menu_closure_animation_.reset();
+#endif
if (item && !menu_stack_.empty() &&
!item->GetDelegate()->ShouldCloseAllMenusOnExecute(item->GetCommand())) {
SetExitType(EXIT_OUTERMOST);
@@ -1926,8 +1952,8 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
pref.set_width(std::max(pref.width(), state_.initial_bounds.width()));
// Don't let the menu go too wide.
- pref.set_width(std::min(pref.width(),
- item->GetDelegate()->GetMaxWidthForMenu(item)));
+ pref.set_width(
+ std::min(pref.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
if (!state_.monitor_bounds.IsEmpty())
pref.set_width(std::min(pref.width(), state_.monitor_bounds.width()));
@@ -2011,7 +2037,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
state_.monitor_bounds.right())
x -= pref.width(); // Move the menu to the left of the button.
else
- x += state_.initial_bounds.width(); // Move the menu right.
+ x += state_.initial_bounds.width(); // Move the menu right.
} else {
// The menu should end with the same x coordinate as the owning
// button.
@@ -2019,7 +2045,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
state_.initial_bounds.x() - pref.width())
x = state_.initial_bounds.right(); // Move right of the button.
else
- x = state_.initial_bounds.x() - pref.width(); // Move left.
+ x = state_.initial_bounds.x() - pref.width(); // Move left.
}
}
item->set_actual_menu_position(orientation);
@@ -2141,6 +2167,12 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
pref.set_width(std::min(pref.width(),
item->GetDelegate()->GetMaxWidthForMenu(item)));
+ const MenuConfig& menu_config = MenuConfig::instance();
+ // Shadow insets are built into MenuScrollView's preferred size so it must be
+ // compensated for when determining the bounds of touchable menus.
+ gfx::Insets shadow_insets = BubbleBorder::GetBorderAndShadowInsets(
+ menu_config.touchable_menu_shadow_elevation);
+
int x, y;
if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
@@ -2158,6 +2190,34 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
}
submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
pref.width() / 2 - x + x_old);
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE) {
+ // Align the left edges of the menu and anchor, and the bottom of the menu
+ // with the top of the anchor.
+ x = owner_bounds.origin().x() - shadow_insets.left();
+ y = owner_bounds.origin().y() - pref.height() + shadow_insets.bottom() -
+ menu_config.touchable_anchor_offset;
+ // Align the right of the container with the right of the app icon.
+ if (x + pref.width() > state_.monitor_bounds.width())
+ x = owner_bounds.right() - pref.width() + shadow_insets.right();
+ // Align the top of the menu with the bottom of the anchor.
+ if (y < 0) {
+ y = owner_bounds.bottom() - shadow_insets.top() +
+ menu_config.touchable_anchor_offset;
+ }
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT) {
+ // Align the right of the menu with the left of the anchor, and the top of
+ // the menu with the top of the anchor.
+ x = owner_bounds.origin().x() - pref.width() + shadow_insets.right() -
+ menu_config.touchable_anchor_offset;
+ y = owner_bounds.origin().y() - shadow_insets.top();
+ // Align the left of the menu with the right of the anchor.
+ if (x < 0) {
+ x = owner_bounds.right() + shadow_insets.left() +
+ menu_config.touchable_anchor_offset;
+ }
+ // Align the bottom of the menu to the bottom of the anchor.
+ if (y + pref.height() > state_.monitor_bounds.height())
+ y = owner_bounds.bottom() - pref.height() + shadow_insets.bottom();
} else {
if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
x = owner_bounds.right() - kBubbleTipSizeLeftRight;
@@ -2316,7 +2376,7 @@ MenuController::SelectByCharDetails MenuController::FindChildForMnemonic(
void MenuController::AcceptOrSelect(MenuItemView* parent,
const SelectByCharDetails& details) {
// This should only be invoked if there is a match.
- DCHECK(details.first_match != -1);
+ DCHECK_NE(details.first_match, -1);
DCHECK(parent->HasSubmenu());
SubmenuView* submenu = parent->GetSubmenu();
DCHECK(submenu);
@@ -2710,4 +2770,12 @@ void MenuController::SetHotTrackedButton(Button* hot_button) {
}
}
+bool MenuController::CanProcessInputEvents() const {
+#if defined(OS_MACOSX)
+ return !menu_closure_animation_;
+#else
+ return true;
+#endif
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 1a056eb2404..b2080448720 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -25,6 +25,10 @@
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/widget/widget_observer.h"
+#if defined(OS_MACOSX)
+#include "ui/views/controls/menu/menu_closure_animation_mac.h"
+#endif
+
namespace ui {
class OSExchangeData;
}
@@ -138,6 +142,7 @@ class VIEWS_EXPORT MenuController
base::TimeTicks closing_event_time() const { return closing_event_time_; }
void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
+ bool is_combobox() const { return is_combobox_; }
// Various events, forwarded from the submenu.
//
@@ -198,6 +203,18 @@ class VIEWS_EXPORT MenuController
// Only used for testing.
static void TurnOffMenuSelectionHoldForTest();
+ void set_use_touchable_layout(bool use_touchable_layout) {
+ use_touchable_layout_ = use_touchable_layout;
+ }
+ bool use_touchable_layout() const { return use_touchable_layout_; }
+
+ // Notifies |this| that |menu_item| is being destroyed.
+ void OnMenuItemDestroying(MenuItemView* menu_item);
+
+ // Returns whether this menu can handle input events right now. This method
+ // can return false while running animations.
+ bool CanProcessInputEvents() const;
+
private:
friend class internal::MenuRunnerImpl;
friend class test::MenuControllerTest;
@@ -338,6 +355,7 @@ class VIEWS_EXPORT MenuController
// Invoked when the user accepts the selected item. This is only used
// when blocking. This schedules the loop to quit.
void Accept(MenuItemView* item, int event_flags);
+ void ReallyAccept(MenuItemView* item, int event_flags);
bool ShowSiblingMenu(SubmenuView* source, const gfx::Point& mouse_location);
@@ -681,6 +699,9 @@ class VIEWS_EXPORT MenuController
// Set to true if the menu item was selected by touch.
bool item_selected_by_touch_ = false;
+ // Whether to use the touchable layout.
+ bool use_touchable_layout_ = false;
+
// During mouse event handling, this is the RootView to forward mouse events
// to. We need this, because if we forward one event to it (e.g., mouse
// pressed), subsequent events (like dragging) should also go to it, even if
@@ -690,6 +711,10 @@ class VIEWS_EXPORT MenuController
// A mask of the EventFlags for the mouse buttons currently pressed.
int current_mouse_pressed_state_ = 0;
+#if defined(OS_MACOSX)
+ std::unique_ptr<MenuClosureAnimationMac> menu_closure_animation_;
+#endif
+
#if defined(USE_AURA)
std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler_;
#endif
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index d8629d3a802..22fa8335af1 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -464,6 +464,7 @@ class MenuControllerTest : public ViewsTestBase {
void Accept(MenuItemView* item, int event_flags) {
menu_controller_->Accept(item, event_flags);
+ views::test::WaitForMenuClosureAnimation();
}
// Causes the |menu_controller_| to begin dragging. Use TestDragDropClient to
@@ -943,6 +944,8 @@ TEST_F(MenuControllerTest, ChildButtonHotTrackedWhenNested) {
// Tests that a menu opened asynchronously, will notify its
// MenuControllerDelegate when Accept is called.
TEST_F(MenuControllerTest, AsynchronousAccept) {
+ views::test::DisableMenuClosureAnimations();
+
MenuController* controller = menu_controller();
controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
MENU_ANCHOR_TOPLEFT, false, false);
@@ -1254,6 +1257,7 @@ TEST_F(MenuControllerTest, AsynchronousRepostEventDeletesController) {
// Tests that having the MenuController deleted during OnGestureEvent does not
// cause a crash. ASAN bots should not detect use-after-free in MenuController.
TEST_F(MenuControllerTest, AsynchronousGestureDeletesController) {
+ views::test::DisableMenuClosureAnimations();
MenuController* controller = menu_controller();
std::unique_ptr<TestMenuControllerDelegate> nested_delegate(
new TestMenuControllerDelegate());
@@ -1277,6 +1281,7 @@ TEST_F(MenuControllerTest, AsynchronousGestureDeletesController) {
// gesture event. The remainder of this test, and TearDown should not crash.
DestroyMenuControllerOnMenuClosed(nested_delegate.get());
controller->OnGestureEvent(sub_menu, &event);
+ views::test::WaitForMenuClosureAnimation();
// Close to remove observers before test TearDown
sub_menu->Close();
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index bcdd4af65ed..f1ff95b4748 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -116,7 +116,9 @@ void MenuHost::InitMenuHost(Widget* parent,
const MenuController* menu_controller =
submenu_->GetMenuItem()->GetMenuController();
const MenuConfig& menu_config = MenuConfig::instance();
- bool rounded_border = menu_controller && menu_config.corner_radius > 0;
+ bool rounded_border =
+ menu_controller && (menu_controller->use_touchable_layout() ||
+ (menu_config.corner_radius > 0));
bool bubble_border = submenu_->GetScrollViewContainer() &&
submenu_->GetScrollViewContainer()->HasBubbleBorder();
params.shadow_type = bubble_border ? Widget::InitParams::SHADOW_TYPE_NONE
diff --git a/chromium/ui/views/controls/menu/menu_host_root_view.cc b/chromium/ui/views/controls/menu/menu_host_root_view.cc
index 362971fa8a4..bb72234feec 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.cc
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.cc
@@ -14,40 +14,41 @@ MenuHostRootView::MenuHostRootView(Widget* widget, SubmenuView* submenu)
: internal::RootView(widget), submenu_(submenu) {}
bool MenuHostRootView::OnMousePressed(const ui::MouseEvent& event) {
- return GetMenuController() &&
- GetMenuController()->OnMousePressed(submenu_, event);
+ return GetMenuControllerForInputEvents() &&
+ GetMenuControllerForInputEvents()->OnMousePressed(submenu_, event);
}
bool MenuHostRootView::OnMouseDragged(const ui::MouseEvent& event) {
- return GetMenuController() &&
- GetMenuController()->OnMouseDragged(submenu_, event);
+ return GetMenuControllerForInputEvents() &&
+ GetMenuControllerForInputEvents()->OnMouseDragged(submenu_, event);
}
void MenuHostRootView::OnMouseReleased(const ui::MouseEvent& event) {
- if (GetMenuController())
- GetMenuController()->OnMouseReleased(submenu_, event);
+ if (GetMenuControllerForInputEvents())
+ GetMenuControllerForInputEvents()->OnMouseReleased(submenu_, event);
}
void MenuHostRootView::OnMouseMoved(const ui::MouseEvent& event) {
- if (GetMenuController())
- GetMenuController()->OnMouseMoved(submenu_, event);
+ if (GetMenuControllerForInputEvents())
+ GetMenuControllerForInputEvents()->OnMouseMoved(submenu_, event);
}
bool MenuHostRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
- return GetMenuController() &&
- GetMenuController()->OnMouseWheel(submenu_, event);
+ return GetMenuControllerForInputEvents() &&
+ GetMenuControllerForInputEvents()->OnMouseWheel(submenu_, event);
}
View* MenuHostRootView::GetTooltipHandlerForPoint(const gfx::Point& point) {
- return GetMenuController()
- ? GetMenuController()->GetTooltipHandlerForPoint(submenu_, point)
+ return GetMenuControllerForInputEvents()
+ ? GetMenuControllerForInputEvents()->GetTooltipHandlerForPoint(
+ submenu_, point)
: nullptr;
}
void MenuHostRootView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
- if (GetMenuController())
- GetMenuController()->ViewHierarchyChanged(submenu_, details);
+ if (GetMenuControllerForInputEvents())
+ GetMenuControllerForInputEvents()->ViewHierarchyChanged(submenu_, details);
RootView::ViewHierarchyChanged(details);
}
@@ -87,4 +88,10 @@ MenuController* MenuHostRootView::GetMenuController() {
return submenu_ ? submenu_->GetMenuItem()->GetMenuController() : NULL;
}
+MenuController* MenuHostRootView::GetMenuControllerForInputEvents() {
+ return GetMenuController() && GetMenuController()->CanProcessInputEvents()
+ ? GetMenuController()
+ : nullptr;
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_host_root_view.h b/chromium/ui/views/controls/menu/menu_host_root_view.h
index 62437f8b1e7..401e6e98db0 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.h
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.h
@@ -47,6 +47,7 @@ class MenuHostRootView : public internal::RootView {
// Returns the MenuController for this MenuHostRootView.
MenuController* GetMenuController();
+ MenuController* GetMenuControllerForInputEvents();
// The SubmenuView we contain.
SubmenuView* submenu_;
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 4cf7d61f7ef..257f71e6eaa 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -199,7 +199,9 @@ bool MenuItemView::IsBubble(MenuAnchorPosition anchor) {
return anchor == MENU_ANCHOR_BUBBLE_LEFT ||
anchor == MENU_ANCHOR_BUBBLE_RIGHT ||
anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
- anchor == MENU_ANCHOR_BUBBLE_BELOW;
+ anchor == MENU_ANCHOR_BUBBLE_BELOW ||
+ anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE ||
+ anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT;
}
// static
@@ -591,6 +593,9 @@ void MenuItemView::Layout() {
(icon_area_width_ - size.width()) / 2;
if (config.icons_in_label || type_ == CHECKBOX || type_ == RADIO)
x = label_start_;
+ if (GetMenuController() && GetMenuController()->use_touchable_layout())
+ x = config.touchable_item_left_margin;
+
int y =
(height() + GetTopMargin() - GetBottomMargin() - size.height()) / 2;
icon_view_->SetPosition(gfx::Point(x, y));
@@ -598,13 +603,15 @@ void MenuItemView::Layout() {
if (radio_check_image_view_) {
int x = config.item_left_margin + left_icon_margin_;
+ if (GetMenuController() && GetMenuController()->use_touchable_layout())
+ x = config.touchable_item_left_margin;
int y =
(height() + GetTopMargin() - GetBottomMargin() - kMenuCheckSize) / 2;
radio_check_image_view_->SetBounds(x, y, kMenuCheckSize, kMenuCheckSize);
}
if (submenu_arrow_image_view_) {
- int x = this->width() - config.arrow_width - config.arrow_to_edge_padding;
+ int x = width() - config.arrow_width - config.arrow_to_edge_padding;
int y =
(height() + GetTopMargin() - GetBottomMargin() - kSubmenuArrowSize) /
2;
@@ -621,6 +628,11 @@ void MenuItemView::SetMargins(int top_margin, int bottom_margin) {
invalidate_dimensions();
}
+void MenuItemView::SetForcedVisualSelection(bool selected) {
+ forced_visual_selection_ = selected;
+ SchedulePaint();
+}
+
MenuItemView::MenuItemView(MenuItemView* parent,
int command,
MenuItemView::Type type)
@@ -647,6 +659,8 @@ MenuItemView::MenuItemView(MenuItemView* parent,
}
MenuItemView::~MenuItemView() {
+ if (GetMenuController())
+ GetMenuController()->OnMenuItemDestroying(this);
delete submenu_;
for (auto* item : removed_items_)
delete item;
@@ -676,6 +690,9 @@ void MenuItemView::UpdateMenuPartSizes() {
padding = (has_icons_ || HasChecksOrRadioButtons()) ?
config.icon_to_label_padding : 0;
}
+ if (GetMenuController() && GetMenuController()->use_touchable_layout())
+ padding = config.touchable_icon_to_label_padding;
+
label_start_ += padding;
EmptyMenuMenuItem menu_item(this);
@@ -815,6 +832,8 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
(mode == PB_NORMAL && IsSelected() &&
parent_menu_item_->GetSubmenu()->GetShowSelection(this) &&
(NonIconChildViewsCount() == 0));
+ if (forced_visual_selection_.has_value())
+ render_selection = *forced_visual_selection_;
MenuDelegate *delegate = GetDelegate();
bool emphasized =
@@ -841,6 +860,8 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
// Calculate some colors.
SkColor fg_color = GetTextColor(false, render_selection, emphasized);
SkColor icon_color = color_utils::DeriveDefaultIconColor(fg_color);
+ if (GetMenuController() && GetMenuController()->use_touchable_layout())
+ icon_color = config.touchable_icon_color;
// Render the check.
if (type_ == CHECKBOX && delegate->IsItemChecked(GetCommand())) {
@@ -870,12 +891,10 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
flags);
if (!subtitle_.empty()) {
canvas->DrawStringRectWithFlags(
- subtitle_,
- font_list,
+ subtitle_, font_list,
GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_MenuItemSubtitleColor),
- text_bounds + gfx::Vector2d(0, font_list.GetHeight()),
- flags);
+ ui::NativeTheme::kColorId_MenuItemMinorTextColor),
+ text_bounds + gfx::Vector2d(0, font_list.GetHeight()), flags);
}
PaintMinorIconAndText(canvas,
@@ -934,7 +953,7 @@ SkColor MenuItemView::GetTextColor(bool minor,
bool render_selection,
bool emphasized) const {
ui::NativeTheme::ColorId color_id =
- minor ? ui::NativeTheme::kColorId_MenuItemSubtitleColor
+ minor ? ui::NativeTheme::kColorId_MenuItemMinorTextColor
: ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor;
if (enabled()) {
if (render_selection)
@@ -1012,6 +1031,34 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
MenuItemDimensions dimensions;
// Get the container height.
dimensions.children_width = child_size.width();
+ const MenuConfig& menu_config = MenuConfig::instance();
+
+ if (GetMenuController() && GetMenuController()->use_touchable_layout()) {
+ // MenuItemViews that use the touchable layout have fixed height and width.
+ dimensions.height = menu_config.touchable_menu_height;
+ dimensions.standard_width = menu_config.touchable_menu_width;
+ return dimensions;
+ }
+
+ const gfx::FontList& font_list = GetFontList();
+ base::string16 minor_text = GetMinorText();
+ if (menu_config.fixed_text_item_height &&
+ menu_config.fixed_container_item_height && menu_config.fixed_menu_width &&
+ GetMenuController() && !GetMenuController()->is_combobox()) {
+ bool has_children = NonIconChildViewsCount() > 0;
+ dimensions.height = has_children ? menu_config.fixed_container_item_height
+ : menu_config.fixed_text_item_height;
+ dimensions.children_width = 0;
+ dimensions.minor_text_width =
+ minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, font_list);
+ int leave_for_minor = dimensions.minor_text_width
+ ? dimensions.minor_text_width +
+ menu_config.label_to_minor_text_padding
+ : 0;
+ dimensions.standard_width = menu_config.fixed_menu_width - leave_for_minor;
+ return dimensions;
+ }
+
dimensions.height = child_size.height();
// Adjust item content height if menu has both items with and without icons.
// This way all menu items will have the same height.
@@ -1025,9 +1072,6 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
if (IsContainer())
return dimensions;
- // Determine the length of the label text.
- const gfx::FontList& font_list = GetFontList();
-
// Get Icon margin overrides for this particular item.
const MenuDelegate* delegate = GetDelegate();
if (delegate) {
@@ -1041,6 +1085,7 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
}
int label_start = GetLabelStartForThisItem();
+ // Determine the length of the label text.
int string_width = gfx::GetStringWidth(title_, font_list);
if (!subtitle_.empty()) {
string_width = std::max(string_width,
@@ -1050,7 +1095,6 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
dimensions.standard_width = string_width + label_start +
item_right_margin_;
// Determine the length of the right-side text.
- base::string16 minor_text = GetMinorText();
dimensions.minor_text_width =
minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, font_list);
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index ab487377b9e..be24fb73cf7 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "ui/base/models/menu_separator_types.h"
@@ -337,6 +338,11 @@ class VIEWS_EXPORT MenuItemView : public View {
use_right_margin_ = use_right_margin;
}
+ // Controls whether this menu has a forced visual selection state. This is
+ // used when animating item acceptance on Mac. Note that once this is set
+ // there's no way to unset it for this MenuItemView!
+ void SetForcedVisualSelection(bool selected);
+
protected:
// Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type);
@@ -556,6 +562,9 @@ class VIEWS_EXPORT MenuItemView : public View {
// The submenu indicator arrow icon in case the menu item has a Submenu.
ImageView* submenu_arrow_image_view_;
+ // The forced visual selection state of this item, if any.
+ base::Optional<bool> forced_visual_selection_;
+
DISALLOW_COPY_AND_ASSIGN(MenuItemView);
};
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index 2a540157090..e1a2339bddb 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -61,59 +61,42 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
MenuItemView* menu,
int menu_index,
int item_id) {
- gfx::Image icon;
- model->GetIconAt(model_index, &icon);
- base::string16 label, sublabel, minor_text;
- const gfx::VectorIcon* minor_icon = nullptr;
- ui::MenuSeparatorType separator_style = ui::NORMAL_SEPARATOR;
- MenuItemView::Type type;
+ base::Optional<MenuItemView::Type> type;
ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index);
-
switch (menu_type) {
case ui::MenuModel::TYPE_COMMAND:
case ui::MenuModel::TYPE_BUTTON_ITEM:
type = MenuItemView::NORMAL;
- label = model->GetLabelAt(model_index);
- sublabel = model->GetSublabelAt(model_index);
- minor_text = model->GetMinorTextAt(model_index);
- minor_icon = model->GetMinorIconAt(model_index);
break;
case ui::MenuModel::TYPE_CHECK:
type = MenuItemView::CHECKBOX;
- label = model->GetLabelAt(model_index);
- sublabel = model->GetSublabelAt(model_index);
- minor_text = model->GetMinorTextAt(model_index);
- minor_icon = model->GetMinorIconAt(model_index);
break;
case ui::MenuModel::TYPE_RADIO:
type = MenuItemView::RADIO;
- label = model->GetLabelAt(model_index);
- sublabel = model->GetSublabelAt(model_index);
- minor_text = model->GetMinorTextAt(model_index);
- minor_icon = model->GetMinorIconAt(model_index);
break;
case ui::MenuModel::TYPE_SEPARATOR:
- icon = gfx::Image();
type = MenuItemView::SEPARATOR;
- separator_style = model->GetSeparatorTypeAt(model_index);
break;
case ui::MenuModel::TYPE_SUBMENU:
type = MenuItemView::SUBMENU;
- label = model->GetLabelAt(model_index);
- sublabel = model->GetSublabelAt(model_index);
- minor_text = model->GetMinorTextAt(model_index);
- minor_icon = model->GetMinorIconAt(model_index);
- break;
- default:
- NOTREACHED();
- type = MenuItemView::NORMAL;
break;
}
+ if (*type == MenuItemView::SEPARATOR) {
+ return menu->AddMenuItemAt(menu_index, item_id, base::string16(),
+ base::string16(), base::string16(), nullptr,
+ gfx::ImageSkia(), *type,
+ model->GetSeparatorTypeAt(model_index));
+ }
+
+ gfx::Image icon;
+ model->GetIconAt(model_index, &icon);
return menu->AddMenuItemAt(
- menu_index, item_id, label, sublabel, minor_text, minor_icon,
- icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), type,
- separator_style);
+ menu_index, item_id, model->GetLabelAt(model_index),
+ model->GetSublabelAt(model_index), model->GetMinorTextAt(model_index),
+ model->GetMinorIconAt(model_index),
+ icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), *type,
+ ui::NORMAL_SEPARATOR);
}
// Static.
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler.cc b/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
index 68c3c94fb9e..9f9dd9448a4 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
@@ -23,7 +23,8 @@ aura::Window* GetOwnerRootWindow(views::Widget* owner) {
MenuPreTargetHandler::MenuPreTargetHandler(MenuController* controller,
Widget* owner)
: controller_(controller), root_(GetOwnerRootWindow(owner)) {
- aura::Env::GetInstanceDontCreate()->PrependPreTargetHandler(this);
+ aura::Env::GetInstanceDontCreate()->AddPreTargetHandler(
+ this, ui::EventTarget::Priority::kSystem);
if (root_) {
wm::GetActivationClient(root_)->AddObserver(this);
root_->AddObserver(this);
diff --git a/chromium/ui/views/controls/menu/menu_runner.h b/chromium/ui/views/controls/menu/menu_runner.h
index 56a53d9dbd1..88b4bb43448 100644
--- a/chromium/ui/views/controls/menu/menu_runner.h
+++ b/chromium/ui/views/controls/menu/menu_runner.h
@@ -95,6 +95,9 @@ class VIEWS_EXPORT MenuRunner {
// shelf uses the flag to continue dragging an item without lifting the
// finger after the context menu of the item is opened.
SEND_GESTURE_EVENTS_TO_OWNER = 1 << 7,
+
+ // Whether to use the touchable layout for this context menu.
+ USE_TOUCHABLE_LAYOUT = 1 << 8,
};
// Creates a new MenuRunner, which may use a native menu if available.
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.cc b/chromium/ui/views/controls/menu/menu_runner_impl.cc
index 0004fe4a546..cd9ac6df3ff 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_impl.cc
@@ -128,6 +128,8 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
controller->set_is_combobox((run_types & MenuRunner::COMBOBOX) != 0);
controller->set_send_gesture_events_to_owner(
(run_types & MenuRunner::SEND_GESTURE_EVENTS_TO_OWNER) != 0);
+ controller->set_use_touchable_layout(
+ (run_types & MenuRunner::USE_TOUCHABLE_LAYOUT) != 0);
controller_ = controller->AsWeakPtr();
menu_->set_controller(controller_.get());
menu_->PrepareForRun(owns_controller_, has_mnemonics,
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 274559a2daf..e68a76f83ed 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -20,10 +20,6 @@ namespace views {
namespace internal {
namespace {
-// The menu run types that should show a native NSMenu rather than a toolkit-
-// views menu. Only supported when the menu is backed by a ui::MenuModel.
-const int kNativeRunTypes = MenuRunner::CONTEXT_MENU | MenuRunner::COMBOBOX;
-
const CGFloat kNativeCheckmarkWidth = 18;
const CGFloat kNativeMenuItemHeight = 18;
@@ -43,7 +39,9 @@ NSMenuItem* FirstCheckedItem(MenuControllerCocoa* menu_controller) {
base::scoped_nsobject<NSView> CreateMenuAnchorView(
NSWindow* window,
const gfx::Rect& screen_bounds,
- NSMenuItem* checked_item) {
+ NSMenuItem* checked_item,
+ CGFloat actual_menu_width,
+ MenuAnchorPosition position) {
NSRect rect = gfx::ScreenRectToNSRect(screen_bounds);
rect = [window convertRectFromScreen:rect];
rect = [[window contentView] convertRect:rect fromView:nil];
@@ -73,6 +71,13 @@ base::scoped_nsobject<NSView> CreateMenuAnchorView(
}
}
+ // When the actual menu width is larger than the anchor, right alignment
+ // should be respected.
+ if (actual_menu_width > rect.size.width &&
+ position == views::MENU_ANCHOR_TOPRIGHT && !base::i18n::IsRTL()) {
+ int width_diff = actual_menu_width - rect.size.width;
+ rect.origin.x -= width_diff;
+ }
// A plain NSView will anchor below rather than "over", so use an NSButton.
base::scoped_nsobject<NSView> anchor_view(
[[NSButton alloc] initWithFrame:rect]);
@@ -118,11 +123,6 @@ MenuRunnerImplInterface* MenuRunnerImplInterface::Create(
ui::MenuModel* menu_model,
int32_t run_types,
const base::Closure& on_menu_closed_callback) {
- if ((run_types & kNativeRunTypes) != 0 &&
- (run_types & MenuRunner::IS_NESTED) == 0) {
- return new MenuRunnerImplCocoa(menu_model, on_menu_closed_callback);
- }
-
return new MenuRunnerImplAdapter(menu_model, on_menu_closed_callback);
}
@@ -159,7 +159,6 @@ void MenuRunnerImplCocoa::RunMenuAt(Widget* parent,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
int32_t run_types) {
- DCHECK(run_types & kNativeRunTypes);
DCHECK(!IsRunning());
DCHECK(parent);
closing_event_time_ = base::TimeTicks();
@@ -175,13 +174,14 @@ void MenuRunnerImplCocoa::RunMenuAt(Widget* parent,
forView:parent->GetNativeView()];
} else if (run_types & MenuRunner::COMBOBOX) {
NSMenuItem* checked_item = FirstCheckedItem(menu_controller_);
- base::scoped_nsobject<NSView> anchor_view(
- CreateMenuAnchorView(window, bounds, checked_item));
NSMenu* menu = [menu_controller_ menu];
+ base::scoped_nsobject<NSView> anchor_view(CreateMenuAnchorView(
+ window, bounds, checked_item, menu.size.width, anchor));
[menu setMinimumWidth:bounds.width() + kNativeCheckmarkWidth];
[menu popUpMenuPositioningItem:checked_item
atLocation:NSZeroPoint
inView:anchor_view];
+
[anchor_view removeFromSuperview];
} else {
NOTREACHED();
diff --git a/chromium/ui/views/controls/menu/menu_runner_unittest.cc b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
index 1ad933bb7d0..79875e46f84 100644
--- a/chromium/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
@@ -9,7 +9,6 @@
#include <memory>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/ui_base_types.h"
#include "ui/events/test/event_generator.h"
@@ -163,6 +162,7 @@ TEST_F(MenuRunnerTest, LatinMnemonic) {
if (IsMus())
return;
+ views::test::DisableMenuClosureAnimations();
InitMenuRunner(0);
MenuRunner* runner = menu_runner();
runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
@@ -171,6 +171,7 @@ TEST_F(MenuRunnerTest, LatinMnemonic) {
ui::test::EventGenerator generator(GetContext(), owner()->GetNativeWindow());
generator.PressKey(ui::VKEY_O, 0);
+ views::test::WaitForMenuClosureAnimation();
EXPECT_FALSE(runner->IsRunning());
TestMenuDelegate* delegate = menu_delegate();
EXPECT_EQ(1, delegate->execute_command_id());
@@ -186,6 +187,7 @@ TEST_F(MenuRunnerTest, NonLatinMnemonic) {
if (IsMus())
return;
+ views::test::DisableMenuClosureAnimations();
InitMenuRunner(0);
MenuRunner* runner = menu_runner();
runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
@@ -195,6 +197,7 @@ TEST_F(MenuRunnerTest, NonLatinMnemonic) {
ui::test::EventGenerator generator(GetContext(), owner()->GetNativeWindow());
ui::KeyEvent key_press(0x062f, ui::VKEY_N, 0);
generator.Dispatch(&key_press);
+ views::test::WaitForMenuClosureAnimation();
EXPECT_FALSE(runner->IsRunning());
TestMenuDelegate* delegate = menu_delegate();
EXPECT_EQ(2, delegate->execute_command_id());
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 01069fe8680..2e2e6b2aa26 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/ax_node_data.h"
@@ -25,7 +24,7 @@ namespace views {
namespace {
-static const int kBorderPaddingDueToRoundedCorners = 1;
+static constexpr int kBorderPaddingDueToRoundedCorners = 1;
// MenuScrollButton ------------------------------------------------------------
@@ -251,7 +250,10 @@ void MenuScrollViewContainer::OnPaintBackground(gfx::Canvas* canvas) {
gfx::Rect bounds(0, 0, width(), height());
NativeTheme::ExtraParams extra;
const MenuConfig& menu_config = MenuConfig::instance();
- extra.menu_background.corner_radius = menu_config.corner_radius;
+ extra.menu_background.corner_radius =
+ content_view_->GetMenuItem()->GetMenuController()->use_touchable_layout()
+ ? menu_config.touchable_corner_radius
+ : menu_config.corner_radius;
GetNativeTheme()->Paint(canvas->sk_canvas(),
NativeTheme::kMenuPopupBackground, NativeTheme::kNormal, bounds, extra);
}
@@ -300,9 +302,19 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
}
void MenuScrollViewContainer::CreateBubbleBorder() {
- bubble_border_ = new BubbleBorder(arrow_,
- BubbleBorder::SMALL_SHADOW,
- SK_ColorWHITE);
+ bubble_border_ =
+ new BubbleBorder(arrow_, BubbleBorder::SMALL_SHADOW, SK_ColorWHITE);
+ if (content_view_->GetMenuItem()
+ ->GetMenuController()
+ ->use_touchable_layout()) {
+ const MenuConfig& menu_config = MenuConfig::instance();
+ bubble_border_->SetCornerRadius(menu_config.touchable_corner_radius);
+ bubble_border_->set_md_shadow_elevation(
+ menu_config.touchable_menu_shadow_elevation);
+ scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(
+ gfx::Insets(menu_config.vertical_touchable_menu_item_padding, 0)));
+ }
+
SetBorder(std::unique_ptr<Border>(bubble_border_));
SetBackground(std::make_unique<BubbleBackground>(bubble_border_));
}
@@ -318,6 +330,9 @@ BubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
return BubbleBorder::BOTTOM_CENTER;
case MENU_ANCHOR_BUBBLE_BELOW:
return BubbleBorder::TOP_CENTER;
+ case MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE:
+ case MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT:
+ return BubbleBorder::FLOAT;
default:
return BubbleBorder::NONE;
}
diff --git a/chromium/ui/views/controls/menu/menu_types.h b/chromium/ui/views/controls/menu/menu_types.h
index 2f9922261f5..d95ce0b33c0 100644
--- a/chromium/ui/views/controls/menu/menu_types.h
+++ b/chromium/ui/views/controls/menu/menu_types.h
@@ -21,7 +21,9 @@ enum MenuAnchorPosition {
MENU_ANCHOR_BUBBLE_LEFT,
MENU_ANCHOR_BUBBLE_RIGHT,
MENU_ANCHOR_BUBBLE_ABOVE,
- MENU_ANCHOR_BUBBLE_BELOW
+ MENU_ANCHOR_BUBBLE_BELOW,
+ MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE,
+ MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT
};
} // 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 a9d8f72b428..3f38a24897c 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/menu/native_menu_win.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index b8926dedbdc..9b244c9e9ea 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -24,10 +24,10 @@
namespace {
// Height of the drop indicator. This should be an even number.
-const int kDropIndicatorHeight = 2;
+constexpr int kDropIndicatorHeight = 2;
// Color of the drop indicator.
-const SkColor kDropIndicatorColor = SK_ColorBLACK;
+constexpr SkColor kDropIndicatorColor = SK_ColorBLACK;
} // namespace
@@ -69,7 +69,7 @@ bool SubmenuView::HasVisibleChildren() {
return false;
}
-int SubmenuView::GetMenuItemCount() {
+int SubmenuView::GetMenuItemCount() const {
int count = 0;
for (int i = 0; i < child_count(); ++i) {
if (child_at(i)->id() == MenuItemView::kMenuItemViewID)
@@ -144,6 +144,8 @@ gfx::Size SubmenuView::CalculatePreferredSize() const {
int max_complex_width = 0;
// The max. width of items which contain a label and maybe an accelerator.
int max_simple_width = 0;
+ // The minimum width of touchable items.
+ int touchable_minimum_width = 0;
// We perform the size calculation in two passes. In the first pass, we
// calculate the width of the menu. In the second, we calculate the height
@@ -163,6 +165,7 @@ gfx::Size SubmenuView::CalculatePreferredSize() const {
std::max(max_minor_text_width_, dimensions.minor_text_width);
max_complex_width = std::max(max_complex_width,
dimensions.standard_width + dimensions.children_width);
+ touchable_minimum_width = dimensions.standard_width;
} else {
max_complex_width = std::max(max_complex_width,
child->GetPreferredSize().width());
@@ -178,6 +181,10 @@ gfx::Size SubmenuView::CalculatePreferredSize() const {
insets.width(),
minimum_preferred_width_ - 2 * insets.width()));
+ if (GetMenuItem()->GetMenuController() &&
+ GetMenuItem()->GetMenuController()->use_touchable_layout())
+ width = std::max(touchable_minimum_width, width);
+
// Then, the height for that width.
int height = 0;
int menu_item_width = width - insets.width();
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index c17c94449e8..9ba69331264 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -56,7 +56,7 @@ class VIEWS_EXPORT SubmenuView : public View,
// Returns the number of child views that are MenuItemViews.
// MenuItemViews are identified by ID.
- int GetMenuItemCount();
+ int GetMenuItemCount() const;
// Returns the MenuItemView at the specified index.
MenuItemView* GetMenuItemAt(int index);
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index df116d35b8a..f15b82824d5 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -48,11 +48,6 @@ void NativeViewHost::Detach() {
Detach(false);
}
-void NativeViewHost::SetPreferredSize(const gfx::Size& size) {
- preferred_size_ = size;
- PreferredSizeChanged();
-}
-
bool NativeViewHost::SetCornerRadius(int corner_radius) {
return native_wrapper_->SetCornerRadius(corner_radius);
}
@@ -73,10 +68,6 @@ void NativeViewHost::NativeViewDestroyed() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, View overrides:
-gfx::Size NativeViewHost::CalculatePreferredSize() const {
- return preferred_size_;
-}
-
void NativeViewHost::Layout() {
if (!native_view_ || !native_wrapper_.get())
return;
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index e1cd204d047..c81cb7443a5 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -47,9 +47,6 @@ class VIEWS_EXPORT NativeViewHost : public View {
// detached before calling this function, and this has no effect in that case.
void Detach();
- // Sets a preferred size for the native view attached to this View.
- void SetPreferredSize(const gfx::Size& size);
-
// Sets the corner radius for clipping gfx::NativeView. Returns true on
// success or false if the platform doesn't support the operation.
// NB: This does not interact nicely with fast_resize.
@@ -86,7 +83,6 @@ class VIEWS_EXPORT NativeViewHost : public View {
void NativeViewDestroyed();
// Overridden from View:
- gfx::Size CalculatePreferredSize() const override;
void Layout() override;
void OnPaint(gfx::Canvas* canvas) override;
void VisibilityChanged(View* starting_from, bool is_visible) override;
@@ -120,9 +116,6 @@ class VIEWS_EXPORT NativeViewHost : public View {
// attached gfx::NativeView.
std::unique_ptr<NativeViewHostWrapper> native_wrapper_;
- // The preferred size of this View
- gfx::Size preferred_size_;
-
// The actual size of the NativeView, or an empty size if no scaling of the
// NativeView should occur.
gfx::Size native_view_size_;
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index fb04f31f2e4..420b005a433 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -10,6 +10,7 @@
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_occlusion_tracker.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/paint_recorder.h"
@@ -106,6 +107,11 @@ void NativeViewHostAura::AttachNativeView() {
}
void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
+ // This method causes a succession of window tree changes.
+ // ScopedPauseOcclusionTracking ensures that occlusion is recomputed at the
+ // end of the method instead of after each change.
+ aura::WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion;
+
clipping_window_delegate_->set_native_view(NULL);
RemoveClippingWindow();
if (!destroyed) {
@@ -143,17 +149,12 @@ void NativeViewHostAura::RemovedFromWidget() {
}
bool NativeViewHostAura::SetCornerRadius(int corner_radius) {
-#if defined(OS_WIN)
- // Layer masks don't work on Windows. See crbug.com/713359
- return false;
-#else
mask_ = views::Painter::CreatePaintedLayer(
views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK,
corner_radius));
mask_->layer()->SetFillsBoundsOpaquely(false);
InstallMask();
return true;
-#endif
}
void NativeViewHostAura::InstallClip(int x, int y, int w, int h) {
diff --git a/chromium/ui/views/controls/progress_bar_unittest.cc b/chromium/ui/views/controls/progress_bar_unittest.cc
index 6eddafe318b..09bb6d807bd 100644
--- a/chromium/ui/views/controls/progress_bar_unittest.cc
+++ b/chromium/ui/views/controls/progress_bar_unittest.cc
@@ -9,10 +9,13 @@
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/color_utils.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/test/views_test_base.h"
namespace views {
-TEST(ProgressBarTest, Accessibility) {
+using ProgressBarTest = ViewsTestBase;
+
+TEST_F(ProgressBarTest, Accessibility) {
ProgressBar bar;
bar.SetValue(0.62);
@@ -26,7 +29,7 @@ TEST(ProgressBarTest, Accessibility) {
}
// Test that default colors can be overridden. Used by Chromecast.
-TEST(ProgressBarTest, OverrideDefaultColors) {
+TEST_F(ProgressBarTest, OverrideDefaultColors) {
ProgressBar bar;
EXPECT_NE(SK_ColorRED, bar.GetForegroundColor());
EXPECT_NE(SK_ColorGREEN, bar.GetBackgroundColor());
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index 31fd358fa1b..06a8b1625c7 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -254,13 +254,22 @@ void ScrollView::SetContents(View* a_view) {
// Protect against clients passing a contents view that has its own Layer.
DCHECK(!a_view->layer());
if (ScrollsWithLayers()) {
- if (!a_view->background() && GetBackgroundColor() != SK_ColorTRANSPARENT) {
- a_view->SetBackground(CreateSolidBackground(GetBackgroundColor()));
+ bool fills_opaquely = true;
+ if (!a_view->background()) {
+ // Contents views may not be aware they need to fill their entire bounds -
+ // play it safe here to avoid graphical glitches
+ // (https://crbug.com/826472). If there's no solid background, mark the
+ // view as not filling its bounds opaquely.
+ if (GetBackgroundColor() != SK_ColorTRANSPARENT)
+ a_view->SetBackground(CreateSolidBackground(GetBackgroundColor()));
+ else
+ fills_opaquely = false;
}
a_view->SetPaintToLayer();
a_view->layer()->SetDidScrollCallback(
base::Bind(&ScrollView::OnLayerScrolled, base::Unretained(this)));
a_view->layer()->SetScrollable(contents_viewport_->bounds().size());
+ a_view->layer()->SetFillsBoundsOpaquely(fills_opaquely);
}
SetHeaderOrContents(contents_viewport_, a_view, &contents_);
}
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index d57fbb058e0..6b818c25420 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/scroll_view.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -134,12 +133,12 @@ class CustomView : public View {
DISALLOW_COPY_AND_ASSIGN(CustomView);
};
-void CheckScrollbarVisibility(const ScrollView& scroll_view,
+void CheckScrollbarVisibility(const ScrollView* scroll_view,
ScrollBarOrientation orientation,
bool should_be_visible) {
const ScrollBar* scrollbar = orientation == HORIZONTAL
- ? scroll_view.horizontal_scroll_bar()
- : scroll_view.vertical_scroll_bar();
+ ? scroll_view->horizontal_scroll_bar()
+ : scroll_view->vertical_scroll_bar();
if (should_be_visible) {
ASSERT_TRUE(scrollbar);
EXPECT_TRUE(scrollbar->visible());
@@ -179,11 +178,16 @@ class ScrollViewTest : public ViewsTestBase {
public:
ScrollViewTest() {}
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+ scroll_view_ = std::make_unique<ScrollView>();
+ }
+
View* InstallContents() {
const gfx::Rect default_outer_bounds(0, 0, 100, 100);
View* contents = new View;
- scroll_view_.SetContents(contents);
- scroll_view_.SetBoundsRect(default_outer_bounds);
+ scroll_view_->SetContents(contents);
+ scroll_view_->SetBoundsRect(default_outer_bounds);
return contents;
}
@@ -208,14 +212,14 @@ class ScrollViewTest : public ViewsTestBase {
protected:
#endif
int VerticalScrollBarWidth() {
- return scroll_view_.vertical_scroll_bar()->GetThickness();
+ return scroll_view_->vertical_scroll_bar()->GetThickness();
}
int HorizontalScrollBarHeight() {
- return scroll_view_.horizontal_scroll_bar()->GetThickness();
+ return scroll_view_->horizontal_scroll_bar()->GetThickness();
}
- ScrollView scroll_view_;
+ std::unique_ptr<ScrollView> scroll_view_;
private:
DISALLOW_COPY_AND_ASSIGN(ScrollViewTest);
@@ -332,7 +336,7 @@ const int WidgetScrollViewTest::kDefaultWidth;
// Verifies the viewport is sized to fit the available space.
TEST_F(ScrollViewTest, ViewportSizedToFit) {
View* contents = InstallContents();
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString());
}
@@ -340,9 +344,9 @@ TEST_F(ScrollViewTest, ViewportSizedToFit) {
// bounded scroll view.
TEST_F(ScrollViewTest, BoundedViewportSizedToFit) {
View* contents = InstallContents();
- scroll_view_.ClipHeightTo(100, 200);
- scroll_view_.SetBorder(CreateSolidBorder(2, 0));
- scroll_view_.Layout();
+ scroll_view_->ClipHeightTo(100, 200);
+ scroll_view_->SetBorder(CreateSolidBorder(2, 0));
+ scroll_view_->Layout();
EXPECT_EQ("2,2 96x96", contents->parent()->bounds().ToString());
// Make sure the width of |contents| is set properly not to overflow the
@@ -355,11 +359,11 @@ TEST_F(ScrollViewTest, BoundedViewportSizedToFit) {
TEST_F(ScrollViewTest, VerticalScrollbarDoesNotAppearUnnecessarily) {
const gfx::Rect default_outer_bounds(0, 0, 100, 100);
View* contents = new VerticalResizingView;
- scroll_view_.SetContents(contents);
- scroll_view_.SetBoundsRect(default_outer_bounds);
- scroll_view_.Layout();
- EXPECT_FALSE(scroll_view_.vertical_scroll_bar()->visible());
- EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
+ scroll_view_->SetContents(contents);
+ scroll_view_->SetBoundsRect(default_outer_bounds);
+ scroll_view_->Layout();
+ EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->visible());
+ EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
}
// Verifies the scrollbars are added as necessary.
@@ -369,54 +373,54 @@ TEST_F(ScrollViewTest, ScrollBars) {
// Size the contents such that vertical scrollbar is needed.
contents->SetBounds(0, 0, 50, 400);
- scroll_view_.Layout();
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ scroll_view_->Layout();
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
contents->parent()->width());
EXPECT_EQ(100, contents->parent()->height());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
- EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
- !scroll_view_.horizontal_scroll_bar()->visible());
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
+ EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
+ !scroll_view_->horizontal_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
// Size the contents such that horizontal scrollbar is needed.
contents->SetBounds(0, 0, 400, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(100, contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(),
contents->parent()->height());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
// Both horizontal and vertical.
contents->SetBounds(0, 0, 300, 400);
- scroll_view_.Layout();
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ scroll_view_->Layout();
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(),
contents->parent()->height());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
// Add a border, test vertical scrollbar.
const int kTopPadding = 1;
const int kLeftPadding = 2;
const int kBottomPadding = 3;
const int kRightPadding = 4;
- scroll_view_.SetBorder(CreateEmptyBorder(kTopPadding, kLeftPadding,
- kBottomPadding, kRightPadding));
+ scroll_view_->SetBorder(CreateEmptyBorder(kTopPadding, kLeftPadding,
+ kBottomPadding, kRightPadding));
contents->SetBounds(0, 0, 50, 400);
- scroll_view_.Layout();
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
+ scroll_view_->Layout();
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth() - kLeftPadding -
kRightPadding,
contents->parent()->width());
EXPECT_EQ(100 - kTopPadding - kBottomPadding, contents->parent()->height());
- EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
- !scroll_view_.horizontal_scroll_bar()->visible());
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
- gfx::Rect bounds = scroll_view_.vertical_scroll_bar()->bounds();
+ EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
+ !scroll_view_->horizontal_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
+ gfx::Rect bounds = scroll_view_->vertical_scroll_bar()->bounds();
EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
EXPECT_EQ(100 - kRightPadding, bounds.right());
EXPECT_EQ(kTopPadding, bounds.y());
@@ -424,16 +428,16 @@ TEST_F(ScrollViewTest, ScrollBars) {
// Horizontal with border.
contents->SetBounds(0, 0, 400, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(100 - kLeftPadding - kRightPadding, contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - kTopPadding -
kBottomPadding,
contents->parent()->height());
- ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
- EXPECT_TRUE(!scroll_view_.vertical_scroll_bar() ||
- !scroll_view_.vertical_scroll_bar()->visible());
- bounds = scroll_view_.horizontal_scroll_bar()->bounds();
+ ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
+ EXPECT_TRUE(!scroll_view_->vertical_scroll_bar() ||
+ !scroll_view_->vertical_scroll_bar()->visible());
+ bounds = scroll_view_->horizontal_scroll_bar()->bounds();
EXPECT_EQ(kLeftPadding, bounds.x());
EXPECT_EQ(100 - kRightPadding, bounds.right());
EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
@@ -441,26 +445,26 @@ TEST_F(ScrollViewTest, ScrollBars) {
// Both horizontal and vertical with border.
contents->SetBounds(0, 0, 300, 400);
- scroll_view_.Layout();
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
+ scroll_view_->Layout();
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth() - kLeftPadding -
kRightPadding,
contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - kTopPadding -
kBottomPadding,
contents->parent()->height());
- bounds = scroll_view_.horizontal_scroll_bar()->bounds();
+ bounds = scroll_view_->horizontal_scroll_bar()->bounds();
// Check horiz.
- ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
- bounds = scroll_view_.horizontal_scroll_bar()->bounds();
+ ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
+ bounds = scroll_view_->horizontal_scroll_bar()->bounds();
EXPECT_EQ(kLeftPadding, bounds.x());
EXPECT_EQ(100 - kRightPadding - VerticalScrollBarWidth(), bounds.right());
EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
EXPECT_EQ(100 - kBottomPadding, bounds.bottom());
// Check vert.
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
- bounds = scroll_view_.vertical_scroll_bar()->bounds();
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
+ bounds = scroll_view_->vertical_scroll_bar()->bounds();
EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
EXPECT_EQ(100 - kRightPadding, bounds.right());
EXPECT_EQ(kTopPadding, bounds.y());
@@ -471,11 +475,11 @@ TEST_F(ScrollViewTest, ScrollBars) {
// Assertions around adding a header.
TEST_F(ScrollViewTest, Header) {
CustomView* header = new CustomView;
- scroll_view_.SetHeader(header);
+ scroll_view_->SetHeader(header);
View* header_parent = header->parent();
View* contents = InstallContents();
- scroll_view_.Layout();
+ scroll_view_->Layout();
// |header|s preferred size is empty, which should result in all space going
// to contents.
EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString());
@@ -502,7 +506,7 @@ TEST_F(ScrollViewTest, Header) {
EXPECT_EQ("0,0 0x0", contents->bounds().ToString());
// Remove the header.
- scroll_view_.SetHeader(NULL);
+ scroll_view_->SetHeader(NULL);
// SetHeader(NULL) deletes header.
header = NULL;
EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString());
@@ -512,111 +516,111 @@ TEST_F(ScrollViewTest, Header) {
// Verifies the scrollbars are added as necessary when a header is present.
TEST_F(ScrollViewTest, ScrollBarsWithHeader) {
CustomView* header = new CustomView;
- scroll_view_.SetHeader(header);
+ scroll_view_->SetHeader(header);
View* contents = InstallContents();
header->SetPreferredSize(gfx::Size(10, 20));
// Size the contents such that vertical scrollbar is needed.
contents->SetBounds(0, 0, 50, 400);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(0, contents->parent()->x());
EXPECT_EQ(20, contents->parent()->y());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
contents->parent()->width());
EXPECT_EQ(80, contents->parent()->height());
EXPECT_EQ(0, header->parent()->x());
EXPECT_EQ(0, header->parent()->y());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
header->parent()->width());
EXPECT_EQ(20, header->parent()->height());
- EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
- !scroll_view_.horizontal_scroll_bar()->visible());
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
+ EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
+ !scroll_view_->horizontal_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
// Make sure the vertical scrollbar overlaps the header for traditional
// scrollbars and doesn't overlap the header for overlay scrollbars.
const int expected_scrollbar_y =
- scroll_view_.vertical_scroll_bar()->OverlapsContent()
+ scroll_view_->vertical_scroll_bar()->OverlapsContent()
? header->bounds().bottom()
: header->y();
- EXPECT_EQ(expected_scrollbar_y, scroll_view_.vertical_scroll_bar()->y());
+ EXPECT_EQ(expected_scrollbar_y, scroll_view_->vertical_scroll_bar()->y());
EXPECT_EQ(header->y(), contents->y());
// Size the contents such that horizontal scrollbar is needed.
contents->SetBounds(0, 0, 400, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(0, contents->parent()->x());
EXPECT_EQ(20, contents->parent()->y());
EXPECT_EQ(100, contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - 20,
contents->parent()->height());
EXPECT_EQ(0, header->parent()->x());
EXPECT_EQ(0, header->parent()->y());
EXPECT_EQ(100, header->parent()->width());
EXPECT_EQ(20, header->parent()->height());
- ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
- EXPECT_TRUE(!scroll_view_.vertical_scroll_bar() ||
- !scroll_view_.vertical_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
+ EXPECT_TRUE(!scroll_view_->vertical_scroll_bar() ||
+ !scroll_view_->vertical_scroll_bar()->visible());
// Both horizontal and vertical.
contents->SetBounds(0, 0, 300, 400);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(0, contents->parent()->x());
EXPECT_EQ(20, contents->parent()->y());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
contents->parent()->width());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - 20,
contents->parent()->height());
EXPECT_EQ(0, header->parent()->x());
EXPECT_EQ(0, header->parent()->y());
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
header->parent()->width());
EXPECT_EQ(20, header->parent()->height());
- ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
- EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
+ EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
}
// Verifies the header scrolls horizontally with the content.
TEST_F(ScrollViewTest, HeaderScrollsWithContent) {
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
CustomView* contents = new CustomView;
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
contents->SetPreferredSize(gfx::Size(500, 500));
CustomView* header = new CustomView;
- scroll_view_.SetHeader(header);
+ scroll_view_->SetHeader(header);
header->SetPreferredSize(gfx::Size(500, 20));
- scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("0,0", header->origin().ToString());
// Scroll the horizontal scrollbar.
- ASSERT_TRUE(scroll_view_.horizontal_scroll_bar());
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 1);
+ ASSERT_TRUE(scroll_view_->horizontal_scroll_bar());
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 1);
EXPECT_EQ("-1,0", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("-1,0", header->origin().ToString());
// Scrolling the vertical scrollbar shouldn't effect the header.
- ASSERT_TRUE(scroll_view_.vertical_scroll_bar());
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 1);
+ ASSERT_TRUE(scroll_view_->vertical_scroll_bar());
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 1);
EXPECT_EQ("-1,-1", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("-1,0", header->origin().ToString());
}
// Verifies ScrollRectToVisible() on the child works.
TEST_F(ScrollViewTest, ScrollRectToVisible) {
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
CustomView* contents = new CustomView;
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
contents->SetPreferredSize(gfx::Size(500, 1000));
- scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
- scroll_view_.Layout();
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+ scroll_view_->Layout();
EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
// Scroll to y=405 height=10, this should make the y position of the content
@@ -625,7 +629,7 @@ TEST_F(ScrollViewTest, ScrollRectToVisible) {
const int viewport_height = test_api.contents_viewport()->height();
// Expect there to be a horizontal scrollbar, making the viewport shorter.
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(), viewport_height);
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(), viewport_height);
gfx::ScrollOffset offset = test_api.CurrentOffset();
EXPECT_EQ(415 - viewport_height, offset.y());
@@ -637,17 +641,17 @@ TEST_F(ScrollViewTest, ScrollRectToVisible) {
// Verifies that child scrolls into view when it's focused.
TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
CustomView* contents = new CustomView;
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
contents->SetPreferredSize(gfx::Size(500, 1000));
FixedView* child = new FixedView;
child->SetPreferredSize(gfx::Size(10, 10));
child->SetPosition(gfx::Point(0, 405));
contents->AddChildView(child);
- scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
- scroll_view_.Layout();
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+ scroll_view_->Layout();
EXPECT_EQ(gfx::Point(), test_api.IntegralViewOffset());
// Set focus to the child control. This should cause the control to scroll to
@@ -657,7 +661,7 @@ TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
const int viewport_height = test_api.contents_viewport()->height();
// Expect there to be a horizontal scrollbar, making the viewport shorter.
- EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(), viewport_height);
+ EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(), viewport_height);
gfx::ScrollOffset offset = test_api.CurrentOffset();
EXPECT_EQ(415 - viewport_height, offset.y());
@@ -666,138 +670,138 @@ TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
// Verifies ClipHeightTo() uses the height of the content when it is between the
// minimum and maximum height values.
TEST_F(ScrollViewTest, ClipHeightToNormalContentHeight) {
- scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
+ scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
const int kNormalContentHeight = 75;
- scroll_view_.SetContents(
+ scroll_view_->SetContents(
new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight)));
EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
- scroll_view_.GetPreferredSize());
+ scroll_view_->GetPreferredSize());
- scroll_view_.SizeToPreferredSize();
- scroll_view_.Layout();
+ scroll_view_->SizeToPreferredSize();
+ scroll_view_->Layout();
EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
- scroll_view_.contents()->size());
- EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view_.size());
+ scroll_view_->contents()->size());
+ EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view_->size());
}
// Verifies ClipHeightTo() uses the minimum height when the content is shorter
// than the minimum height value.
TEST_F(ScrollViewTest, ClipHeightToShortContentHeight) {
- scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
+ scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
const int kShortContentHeight = 10;
View* contents =
new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight));
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
- EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.GetPreferredSize());
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->GetPreferredSize());
- scroll_view_.SizeToPreferredSize();
- scroll_view_.Layout();
+ scroll_view_->SizeToPreferredSize();
+ scroll_view_->Layout();
// Layered scrolling requires the contents to fill the viewport.
if (contents->layer()) {
- EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.contents()->size());
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->contents()->size());
} else {
EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
- scroll_view_.contents()->size());
+ scroll_view_->contents()->size());
}
- EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.size());
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->size());
}
// Verifies ClipHeightTo() uses the maximum height when the content is longer
// thamn the maximum height value.
TEST_F(ScrollViewTest, ClipHeightToTallContentHeight) {
- scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
+ scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
const int kTallContentHeight = 1000;
- scroll_view_.SetContents(
+ scroll_view_->SetContents(
new views::StaticSizedView(gfx::Size(kWidth, kTallContentHeight)));
- EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.GetPreferredSize());
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->GetPreferredSize());
- scroll_view_.SizeToPreferredSize();
- scroll_view_.Layout();
+ scroll_view_->SizeToPreferredSize();
+ scroll_view_->Layout();
// The width may be less than kWidth if the scroll bar takes up some width.
- EXPECT_GE(kWidth, scroll_view_.contents()->width());
- EXPECT_EQ(kTallContentHeight, scroll_view_.contents()->height());
- EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
+ EXPECT_GE(kWidth, scroll_view_->contents()->width());
+ EXPECT_EQ(kTallContentHeight, scroll_view_->contents()->height());
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->size());
}
// Verifies that when ClipHeightTo() produces a scrollbar, it reduces the width
// of the inner content of the ScrollView.
TEST_F(ScrollViewTest, ClipHeightToScrollbarUsesWidth) {
- scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
+ scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
// Create a view that will be much taller than it is wide.
- scroll_view_.SetContents(new views::ProportionallySizedView(1000));
+ scroll_view_->SetContents(new views::ProportionallySizedView(1000));
// Without any width, it will default to 0,0 but be overridden by min height.
- scroll_view_.SizeToPreferredSize();
- EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view_.GetPreferredSize());
+ scroll_view_->SizeToPreferredSize();
+ EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view_->GetPreferredSize());
- gfx::Size new_size(kWidth, scroll_view_.GetHeightForWidth(kWidth));
- scroll_view_.SetSize(new_size);
- scroll_view_.Layout();
+ gfx::Size new_size(kWidth, scroll_view_->GetHeightForWidth(kWidth));
+ scroll_view_->SetSize(new_size);
+ scroll_view_->Layout();
- int expected_width = kWidth - scroll_view_.GetScrollBarLayoutWidth();
- EXPECT_EQ(scroll_view_.contents()->size().width(), expected_width);
- EXPECT_EQ(scroll_view_.contents()->size().height(), 1000 * expected_width);
- EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
+ int expected_width = kWidth - scroll_view_->GetScrollBarLayoutWidth();
+ EXPECT_EQ(scroll_view_->contents()->size().width(), expected_width);
+ EXPECT_EQ(scroll_view_->contents()->size().height(), 1000 * expected_width);
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->size());
}
TEST_F(ScrollViewTest, CornerViewVisibility) {
View* contents = InstallContents();
- View* corner_view = ScrollViewTestApi(&scroll_view_).corner_view();
+ View* corner_view = ScrollViewTestApi(scroll_view_.get()).corner_view();
contents->SetBounds(0, 0, 200, 200);
- scroll_view_.Layout();
+ scroll_view_->Layout();
// Corner view should not exist if using overlay scrollbars.
- if (scroll_view_.vertical_scroll_bar()->OverlapsContent()) {
+ if (scroll_view_->vertical_scroll_bar()->OverlapsContent()) {
EXPECT_FALSE(corner_view->parent());
return;
}
// Corner view should be visible when both scrollbars are visible.
- EXPECT_EQ(&scroll_view_, corner_view->parent());
+ EXPECT_EQ(scroll_view_.get(), corner_view->parent());
EXPECT_TRUE(corner_view->visible());
// Corner view should be aligned to the scrollbars.
- EXPECT_EQ(scroll_view_.vertical_scroll_bar()->x(), corner_view->x());
- EXPECT_EQ(scroll_view_.horizontal_scroll_bar()->y(), corner_view->y());
- EXPECT_EQ(scroll_view_.GetScrollBarLayoutWidth(), corner_view->width());
- EXPECT_EQ(scroll_view_.GetScrollBarLayoutHeight(), corner_view->height());
+ EXPECT_EQ(scroll_view_->vertical_scroll_bar()->x(), corner_view->x());
+ EXPECT_EQ(scroll_view_->horizontal_scroll_bar()->y(), corner_view->y());
+ EXPECT_EQ(scroll_view_->GetScrollBarLayoutWidth(), corner_view->width());
+ EXPECT_EQ(scroll_view_->GetScrollBarLayoutHeight(), corner_view->height());
// Corner view should be removed when only the vertical scrollbar is visible.
contents->SetBounds(0, 0, 50, 200);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_FALSE(corner_view->parent());
// ... or when only the horizontal scrollbar is visible.
contents->SetBounds(0, 0, 200, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_FALSE(corner_view->parent());
// ... or when no scrollbar is visible.
contents->SetBounds(0, 0, 50, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_FALSE(corner_view->parent());
// Corner view should reappear when both scrollbars reappear.
contents->SetBounds(0, 0, 200, 200);
- scroll_view_.Layout();
- EXPECT_EQ(&scroll_view_, corner_view->parent());
+ scroll_view_->Layout();
+ EXPECT_EQ(scroll_view_.get(), corner_view->parent());
EXPECT_TRUE(corner_view->visible());
}
TEST_F(ScrollViewTest, ChildWithLayerTest) {
View* contents = InstallContents();
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
if (test_api.contents_viewport()->layer())
return;
@@ -812,7 +816,7 @@ TEST_F(ScrollViewTest, ChildWithLayerTest) {
EXPECT_TRUE(test_api.contents_viewport()->layer()->fills_bounds_opaquely());
// Setting a transparent color should make fills opaquely false.
- scroll_view_.SetBackgroundColor(SK_ColorTRANSPARENT);
+ scroll_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
EXPECT_FALSE(test_api.contents_viewport()->layer()->fills_bounds_opaquely());
child->DestroyLayer();
@@ -829,12 +833,12 @@ TEST_F(ScrollViewTest, ChildWithLayerTest) {
// is added to the ScrollView's viewport.
TEST_F(ScrollViewTest, DontCreateLayerOnViewportIfLayerOnScrollViewCreated) {
View* contents = InstallContents();
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
if (test_api.contents_viewport()->layer())
return;
- scroll_view_.SetPaintToLayer();
+ scroll_view_->SetPaintToLayer();
View* child = new View();
contents->AddChildView(child);
@@ -853,35 +857,35 @@ TEST_F(ScrollViewTest, CocoaOverlayScrollBars) {
// Size the contents such that vertical scrollbar is needed.
// Since it is overlaid, the ViewPort size should match the ScrollView.
contents->SetBounds(0, 0, 50, 400);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(100, contents->parent()->width());
EXPECT_EQ(100, contents->parent()->height());
- EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
+ EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutWidth());
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
// Size the contents such that horizontal scrollbar is needed.
contents->SetBounds(0, 0, 400, 50);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(100, contents->parent()->width());
EXPECT_EQ(100, contents->parent()->height());
- EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+ EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutHeight());
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
// Both horizontal and vertical scrollbars.
contents->SetBounds(0, 0, 300, 400);
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(100, contents->parent()->width());
EXPECT_EQ(100, contents->parent()->height());
- EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
- EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+ EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutWidth());
+ EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutHeight());
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
// Make sure the horizontal and vertical scrollbars don't overlap each other.
- gfx::Rect vert_bounds = scroll_view_.vertical_scroll_bar()->bounds();
- gfx::Rect horiz_bounds = scroll_view_.horizontal_scroll_bar()->bounds();
+ gfx::Rect vert_bounds = scroll_view_->vertical_scroll_bar()->bounds();
+ gfx::Rect horiz_bounds = scroll_view_->horizontal_scroll_bar()->bounds();
EXPECT_EQ(vert_bounds.x(), horiz_bounds.right());
EXPECT_EQ(horiz_bounds.y(), vert_bounds.bottom());
@@ -982,11 +986,11 @@ TEST_F(WidgetScrollViewTest, ScrollersOnRest) {
// Test that increasing the size of the viewport "below" scrolled content causes
// the content to scroll up so that it still fills the viewport.
TEST_F(ScrollViewTest, ConstrainScrollToBounds) {
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
View* contents = InstallContents();
contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(gfx::ScrollOffset(), test_api.CurrentOffset());
@@ -996,49 +1000,49 @@ TEST_F(ScrollViewTest, ConstrainScrollToBounds) {
EXPECT_NE(gfx::ScrollOffset(), fully_scrolled);
// Making the viewport 55 pixels taller should scroll up the same amount.
- scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 155));
- scroll_view_.Layout();
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 155));
+ scroll_view_->Layout();
EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
EXPECT_EQ(fully_scrolled.x(), test_api.CurrentOffset().x());
// And 77 pixels wider should scroll left. Also make it short again: the y-
// offset from the last change should remain.
- scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 177, 100));
- scroll_view_.Layout();
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 177, 100));
+ scroll_view_->Layout();
EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
EXPECT_EQ(fully_scrolled.x() - 77, test_api.CurrentOffset().x());
}
// Calling Layout on ScrollView should not reset the scroll location.
TEST_F(ScrollViewTest, ContentScrollNotResetOnLayout) {
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
CustomView* contents = new CustomView;
contents->SetPreferredSize(gfx::Size(300, 300));
- scroll_view_.SetContents(contents);
- scroll_view_.ClipHeightTo(0, 150);
- scroll_view_.SizeToPreferredSize();
+ scroll_view_->SetContents(contents);
+ scroll_view_->ClipHeightTo(0, 150);
+ scroll_view_->SizeToPreferredSize();
// ScrollView preferred width matches that of |contents|, with the height
// capped at the value we clipped to.
- EXPECT_EQ(gfx::Size(300, 150), scroll_view_.size());
+ EXPECT_EQ(gfx::Size(300, 150), scroll_view_->size());
// Scroll down.
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 25);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 25);
EXPECT_EQ(25, test_api.CurrentOffset().y());
// Call Layout; no change to scroll position.
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(25, test_api.CurrentOffset().y());
// Change contents of |contents|, call Layout; still no change to scroll
// position.
contents->SetPreferredSize(gfx::Size(300, 500));
contents->InvalidateLayout();
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(25, test_api.CurrentOffset().y());
// Change |contents| to be shorter than the ScrollView's clipped height.
// This /will/ change the scroll location due to ConstrainScrollToBounds.
contents->SetPreferredSize(gfx::Size(300, 50));
- scroll_view_.Layout();
+ scroll_view_->Layout();
EXPECT_EQ(0, test_api.CurrentOffset().y());
}
@@ -1046,16 +1050,16 @@ TEST_F(ScrollViewTest, ContentScrollNotResetOnLayout) {
TEST_F(ScrollViewTest, VerticalOverflowIndicators) {
const int kWidth = 100;
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
// Set up with vertical scrollbar.
FixedView* contents = new FixedView;
contents->SetPreferredSize(gfx::Size(kWidth, kMaxHeight * 5));
- scroll_view_.SetContents(contents);
- scroll_view_.ClipHeightTo(0, kMaxHeight);
+ scroll_view_->SetContents(contents);
+ scroll_view_->ClipHeightTo(0, kMaxHeight);
// Make sure the size is set such that no horizontal scrollbar gets shown.
- scroll_view_.SetSize(
+ scroll_view_->SetSize(
gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
kMaxHeight));
@@ -1064,8 +1068,8 @@ TEST_F(ScrollViewTest, VerticalOverflowIndicators) {
// The vertical scroll bar should be visible and the horizontal scroll bar
// should not.
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
// The overflow indicator on the bottom should be visible.
EXPECT_TRUE(test_api.more_content_bottom()->visible());
@@ -1079,7 +1083,7 @@ TEST_F(ScrollViewTest, VerticalOverflowIndicators) {
// Now scroll the view to someplace in the middle of the scrollable region.
int offset = kMaxHeight * 2;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
// At this point, both overflow indicators on the top and bottom should be
@@ -1093,7 +1097,7 @@ TEST_F(ScrollViewTest, VerticalOverflowIndicators) {
// Finally scroll the view to end of the scrollable region.
offset = kMaxHeight * 4;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
// The overflow indicator on the bottom should not be visible.
@@ -1111,15 +1115,15 @@ TEST_F(ScrollViewTest, HorizontalOverflowIndicators) {
const int kWidth = 100;
const int kHeight = 100;
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
// Set up with horizontal scrollbar.
FixedView* contents = new FixedView;
contents->SetPreferredSize(gfx::Size(kWidth * 5, kHeight));
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
// Make sure the size is set such that no vertical scrollbar gets shown.
- scroll_view_.SetSize(gfx::Size(
+ scroll_view_->SetSize(gfx::Size(
kWidth, kHeight + test_api.GetBaseScrollBar(HORIZONTAL)->GetThickness()));
contents->SetBounds(0, 0, kWidth * 5, kHeight);
@@ -1129,8 +1133,8 @@ TEST_F(ScrollViewTest, HorizontalOverflowIndicators) {
// The horizontal scroll bar should be visible and the vertical scroll bar
// should not.
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
- CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
// The overflow indicator on the right should be visible.
EXPECT_TRUE(test_api.more_content_right()->visible());
@@ -1144,7 +1148,7 @@ TEST_F(ScrollViewTest, HorizontalOverflowIndicators) {
// Now scroll the view to someplace in the middle of the scrollable region.
int offset = kWidth * 2;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
// At this point, both overflow indicators on the left and right should be
@@ -1158,7 +1162,7 @@ TEST_F(ScrollViewTest, HorizontalOverflowIndicators) {
// Finally scroll the view to end of the scrollable region.
offset = kWidth * 4;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
// The overflow indicator on the right should not be visible.
@@ -1176,22 +1180,22 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
const int kWidth = 100;
const int kHeight = 100;
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
// Set up with both horizontal and vertical scrollbars.
FixedView* contents = new FixedView;
contents->SetPreferredSize(gfx::Size(kWidth * 5, kHeight * 5));
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
// Make sure the size is set such that both scrollbars are shown.
- scroll_view_.SetSize(gfx::Size(kWidth, kHeight));
+ scroll_view_->SetSize(gfx::Size(kWidth, kHeight));
// Make sure the initial origin is 0,0
EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
// The horizontal and vertical scroll bars should be visible.
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
// The overflow indicators on the right and bottom should not be visible since
// they are against the scrollbars.
@@ -1205,8 +1209,8 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
// Now scroll the view to someplace in the middle of the horizontal scrollable
// region.
int offset_x = kWidth * 2;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
- offset_x);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+ offset_x);
EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
// Since there is a vertical scrollbar only the overflow indicator on the left
@@ -1220,8 +1224,8 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
// Next, scroll the view to end of the scrollable region.
offset_x = kWidth * 4;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
- offset_x);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+ offset_x);
EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
// The overflow indicator on the right should still not be visible.
@@ -1237,7 +1241,7 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
EXPECT_FALSE(test_api.more_content_bottom()->visible());
// Return the view back to the horizontal origin.
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 0);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 0);
EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
// The overflow indicators on the right and bottom should not be visible since
@@ -1253,7 +1257,7 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
// Now scroll the view to somplace in the middle of the vertical scrollable
// region.
int offset_y = kHeight * 2;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
// Similar to the above, since there is a horizontal scrollbar only the
@@ -1268,7 +1272,7 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
// Finally, for the vertical test scroll the region all the way to the end.
offset_y = kHeight * 4;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
// The overflow indicator on the bottom should still not be visible.
@@ -1286,8 +1290,8 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
// Back to the horizontal. Scroll all the way to the end in the horizontal
// direction.
offset_x = kWidth * 4;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
- offset_x);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+ offset_x);
EXPECT_EQ(gfx::ScrollOffset(offset_x, offset_y), test_api.CurrentOffset());
// The overflow indicator on the bottom and right should still not be visible.
@@ -1302,19 +1306,19 @@ TEST_F(ScrollViewTest, HorizontalVerticalOverflowIndicators) {
TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
const int kWidth = 100;
- ScrollViewTestApi test_api(&scroll_view_);
+ ScrollViewTestApi test_api(scroll_view_.get());
// Set up with vertical scrollbar and a header.
FixedView* contents = new FixedView;
CustomView* header = new CustomView;
contents->SetPreferredSize(gfx::Size(kWidth, kMaxHeight * 5));
- scroll_view_.SetContents(contents);
+ scroll_view_->SetContents(contents);
header->SetPreferredSize(gfx::Size(10, 20));
- scroll_view_.SetHeader(header);
- scroll_view_.ClipHeightTo(0, kMaxHeight + header->height());
+ scroll_view_->SetHeader(header);
+ scroll_view_->ClipHeightTo(0, kMaxHeight + header->height());
// Make sure the size is set such that no horizontal scrollbar gets shown.
- scroll_view_.SetSize(
+ scroll_view_->SetSize(
gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
kMaxHeight + header->height()));
@@ -1323,8 +1327,8 @@ TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
// The vertical scroll bar should be visible and the horizontal scroll bar
// should not.
- CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
- CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
// The overflow indicator on the bottom should be visible.
EXPECT_TRUE(test_api.more_content_bottom()->visible());
@@ -1338,7 +1342,7 @@ TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
// Now scroll the view to someplace in the middle of the scrollable region.
int offset = kMaxHeight * 2;
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
// At this point, only the overflow indicator on the bottom should be visible
@@ -1353,7 +1357,7 @@ TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
// Finally scroll the view to end of the scrollable region.
offset = test_api.GetBaseScrollBar(VERTICAL)->GetMaxPosition();
- scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+ scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
// The overflow indicator on the bottom should not be visible now.
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 1515c68c296..5e7982dcdb9 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -13,6 +13,7 @@
#include "base/i18n/rtl.h"
#include "base/strings/string_util.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_elider.h"
#include "ui/gfx/text_utils.h"
@@ -225,6 +226,15 @@ gfx::Insets StyledLabel::GetInsets() const {
return insets;
}
+void StyledLabel::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ if (text_context_ == style::CONTEXT_DIALOG_TITLE)
+ node_data->role = ax::mojom::Role::kTitleBar;
+ else
+ node_data->role = ax::mojom::Role::kStaticText;
+
+ node_data->SetName(text());
+}
+
gfx::Size StyledLabel::CalculatePreferredSize() const {
return calculated_size_;
}
diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h
index 6dc8e734bdc..3268ad50e2c 100644
--- a/chromium/ui/views/controls/styled_label.h
+++ b/chromium/ui/views/controls/styled_label.h
@@ -127,6 +127,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// View:
const char* GetClassName() const override;
gfx::Insets GetInsets() const override;
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int w) const override;
void Layout() override;
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 7c44a024a40..bc33e72aca4 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -286,9 +286,7 @@ void Tab::OnPaint(gfx::Canvas* canvas) {
void Tab::GetAccessibleNodeData(ui::AXNodeData* data) {
data->role = ax::mojom::Role::kTab;
data->SetName(title()->text());
- data->AddState(ax::mojom::State::kSelectable);
- if (selected())
- data->AddState(ax::mojom::State::kSelected);
+ data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, selected());
}
bool Tab::HandleAccessibleAction(const ui::AXActionData& action_data) {
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
index 02bb3cf82c8..f499e202ee4 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -32,7 +32,10 @@ base::string16 DefaultTabTitle() {
class TabbedPaneTest : public ViewsTestBase {
public:
- TabbedPaneTest() {
+ TabbedPaneTest() = default;
+
+ void SetUp() override {
+ ViewsTestBase::SetUp();
tabbed_pane_ = std::make_unique<TabbedPane>();
tabbed_pane_->set_owned_by_client();
}
@@ -226,8 +229,8 @@ TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) {
EXPECT_EQ(ax::mojom::Role::kTab, data.role);
EXPECT_EQ(DefaultTabTitle(),
data.GetString16Attribute(ax::mojom::StringAttribute::kName));
- EXPECT_TRUE(data.HasState(ax::mojom::State::kSelectable));
- EXPECT_EQ(i == 0, data.HasState(ax::mojom::State::kSelected));
+ EXPECT_EQ(i == 0,
+ data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
}
ui::AXActionData action;
diff --git a/chromium/ui/views/controls/table/table_header.cc b/chromium/ui/views/controls/table/table_header.cc
index dd72a413579..8c5b20fdfe8 100644
--- a/chromium/ui/views/controls/table/table_header.cc
+++ b/chromium/ui/views/controls/table/table_header.cc
@@ -242,7 +242,7 @@ bool TableHeader::StartResize(const ui::LocatedEvent& event) {
resize_details_.reset(new ColumnResizeDetails);
resize_details_->column_index = index;
resize_details_->initial_x = event.root_location().x();
- resize_details_->initial_width = table_->visible_columns()[index].width;
+ resize_details_->initial_width = table_->GetVisibleColumn(index).width;
return true;
}
@@ -253,9 +253,15 @@ void TableHeader::ContinueResize(const ui::LocatedEvent& event) {
const int scale = base::i18n::IsRTL() ? -1 : 1;
const int delta = scale *
(event.root_location().x() - resize_details_->initial_x);
+ const TableView::VisibleColumn& column =
+ table_->GetVisibleColumn(resize_details_->column_index);
+ const int needed_for_title =
+ gfx::GetStringWidth(column.column.title, font_list_) +
+ 2 * kHorizontalPadding;
table_->SetVisibleColumnWidth(
resize_details_->column_index,
- std::max(kMinColumnWidth, resize_details_->initial_width + delta));
+ std::max({kMinColumnWidth, needed_for_title,
+ resize_details_->initial_width + delta}));
}
void TableHeader::ToggleSortOrder(const ui::LocatedEvent& event) {
@@ -264,7 +270,7 @@ void TableHeader::ToggleSortOrder(const ui::LocatedEvent& event) {
const int x = GetMirroredXInView(event.x());
const int index = GetClosestVisibleColumnIndex(table_, x);
- const TableView::VisibleColumn& column(table_->visible_columns()[index]);
+ const TableView::VisibleColumn& column(table_->GetVisibleColumn(index));
if (x >= column.x && x < column.x + column.width && event.y() >= 0 &&
event.y() < height())
table_->ToggleSortOrder(index);
@@ -277,7 +283,7 @@ int TableHeader::GetResizeColumn(int x) const {
const int index = GetClosestVisibleColumnIndex(table_, x);
DCHECK_NE(-1, index);
- const TableView::VisibleColumn& column(table_->visible_columns()[index]);
+ const TableView::VisibleColumn& column(table_->GetVisibleColumn(index));
if (index > 0 && x >= column.x - kResizePadding &&
x <= column.x + kResizePadding) {
return index - 1;
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index a6c8234c5cb..d7f37cf103f 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -287,6 +287,11 @@ bool TableView::HasColumn(int id) const {
return false;
}
+const TableView::VisibleColumn& TableView::GetVisibleColumn(int index) {
+ DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
+ return visible_columns_[index];
+}
+
void TableView::SetVisibleColumnWidth(int index, int width) {
DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
if (visible_columns_[index].width == width)
@@ -458,9 +463,9 @@ void TableView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kRow;
node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
selection_model_.active());
- if (selection_model_.IsSelected(selection_model_.active())) {
- node_data->AddState(ax::mojom::State::kSelected);
- }
+ node_data->AddBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected,
+ selection_model_.IsSelected(selection_model_.active()));
// Generate accessible name from column headers and selected cell text.
std::vector<base::string16> name_parts;
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index b62e21ce5ef..eca7e3ed55f 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -139,6 +139,8 @@ class VIEWS_EXPORT TableView
return visible_columns_;
}
+ const VisibleColumn& GetVisibleColumn(int index);
+
// Sets the width of the column. |index| is in terms of |visible_columns_|.
void SetVisibleColumnWidth(int index, int width);
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index e5f895ecfd9..88df9b24fd8 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -12,6 +12,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/controls/table/table_grouper.h"
#include "ui/views/controls/table/table_header.h"
#include "ui/views/controls/table/table_view_observer.h"
@@ -46,6 +47,8 @@ class TableViewTestHelper {
table_->SetSelectionModel(new_selection);
}
+ const gfx::FontList& font_list() { return table_->font_list_; }
+
private:
TableView* table_;
@@ -197,7 +200,7 @@ std::string GetRowsInViewOrderAsString(TableView* table) {
// Format row |i| like this: "[value1, value2, value3]"
result += "[";
for (size_t j = 0; j < table->visible_columns().size(); ++j) {
- const ui::TableColumn& column = table->visible_columns()[j].column;
+ const ui::TableColumn& column = table->GetVisibleColumn(j).column;
if (j != 0)
result += ", "; // Comma between each value in the row.
@@ -209,6 +212,27 @@ std::string GetRowsInViewOrderAsString(TableView* table) {
return result;
}
+bool PressLeftMouseAt(views::View* target, const gfx::Point& point) {
+ const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ return target->OnMousePressed(pressed);
+}
+
+void ReleaseLeftMouseAt(views::View* target, const gfx::Point& point) {
+ const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ target->OnMouseReleased(release);
+}
+
+bool DragLeftMouseTo(views::View* target, const gfx::Point& point) {
+ const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, point, point,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ 0);
+ return target->OnMouseDragged(dragged);
+}
+
} // namespace
class TableViewTest : public ViewsTestBase {
@@ -324,7 +348,7 @@ TEST_F(TableViewTest, ColumnVisibility) {
// Hide the first column.
table_->SetColumnVisibility(0, false);
ASSERT_EQ(1u, helper_->visible_col_count());
- EXPECT_EQ(1, table_->visible_columns()[0].column.id);
+ EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
// Hide the second column.
@@ -334,40 +358,33 @@ TEST_F(TableViewTest, ColumnVisibility) {
// Show the second column.
table_->SetColumnVisibility(1, true);
ASSERT_EQ(1u, helper_->visible_col_count());
- EXPECT_EQ(1, table_->visible_columns()[0].column.id);
+ EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
// Show the first column.
table_->SetColumnVisibility(0, true);
ASSERT_EQ(2u, helper_->visible_col_count());
- EXPECT_EQ(1, table_->visible_columns()[0].column.id);
- EXPECT_EQ(0, table_->visible_columns()[1].column.id);
+ EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
+ EXPECT_EQ(0, table_->GetVisibleColumn(1).column.id);
EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
}
// Verifies resizing a column works.
TEST_F(TableViewTest, Resize) {
- const int x = table_->visible_columns()[0].width;
+ const int x = table_->GetVisibleColumn(0).width;
EXPECT_NE(0, x);
// Drag the mouse 1 pixel to the left.
- const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- helper_->header()->OnMousePressed(pressed);
- const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, gfx::Point(x - 1, 0),
- gfx::Point(x - 1, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- helper_->header()->OnMouseDragged(dragged);
+ PressLeftMouseAt(helper_->header(), gfx::Point(x, 0));
+ DragLeftMouseTo(helper_->header(), gfx::Point(x - 1, 0));
// This should shrink the first column and pull the second column in.
- EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
- EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
+ EXPECT_EQ(x - 1, table_->GetVisibleColumn(0).width);
+ EXPECT_EQ(x - 1, table_->GetVisibleColumn(1).x);
}
// Verifies resizing a column works with a gesture.
TEST_F(TableViewTest, ResizeViaGesture) {
- const int x = table_->visible_columns()[0].width;
+ const int x = table_->GetVisibleColumn(0).width;
EXPECT_NE(0, x);
// Drag the mouse 1 pixel to the left.
ui::GestureEvent scroll_begin(
@@ -380,8 +397,27 @@ TEST_F(TableViewTest, ResizeViaGesture) {
helper_->header()->OnGestureEvent(&scroll_update);
// This should shrink the first column and pull the second column in.
- EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
- EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
+ EXPECT_EQ(x - 1, table_->GetVisibleColumn(0).width);
+ EXPECT_EQ(x - 1, table_->GetVisibleColumn(1).x);
+}
+
+// Verifies resizing a column won't reduce the column width below the width of
+// the column's title text.
+TEST_F(TableViewTest, ResizeHonorsMinimum) {
+ TableViewTestHelper helper(table_);
+ const int x = table_->GetVisibleColumn(0).width;
+ EXPECT_NE(0, x);
+
+ PressLeftMouseAt(helper_->header(), gfx::Point(x, 0));
+ DragLeftMouseTo(helper_->header(), gfx::Point(20, 0));
+
+ int title_width = gfx::GetStringWidth(
+ table_->GetVisibleColumn(0).column.title, helper.font_list());
+ EXPECT_LT(title_width, table_->GetVisibleColumn(0).width);
+
+ int old_width = table_->GetVisibleColumn(0).width;
+ DragLeftMouseTo(helper_->header(), gfx::Point(old_width + 10, 0));
+ EXPECT_EQ(old_width + 10, table_->GetVisibleColumn(0).width);
}
// Assertions for table sorting.
@@ -519,20 +555,12 @@ TEST_F(TableViewTest, Sort) {
TEST_F(TableViewTest, SortOnMouse) {
EXPECT_TRUE(table_->sort_descriptors().empty());
- const int x = table_->visible_columns()[0].width / 2;
+ const int x = table_->GetVisibleColumn(0).width / 2;
EXPECT_NE(0, x);
// Press and release the mouse.
- const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
// The header must return true, else it won't normally get the release.
- EXPECT_TRUE(helper_->header()->OnMousePressed(pressed));
- const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(x, 0),
- gfx::Point(x, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- helper_->header()->OnMouseReleased(release);
+ EXPECT_TRUE(PressLeftMouseAt(helper_->header(), gfx::Point(x, 0)));
+ ReleaseLeftMouseAt(helper_->header(), gfx::Point(x, 0));
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index d02b648714c..6cd683a7ee9 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -58,7 +57,7 @@
#if defined(OS_WIN)
#include "base/win/win_util.h"
-#include "ui/base/win/osk_display_manager.h"
+#include "ui/base/ime/win/osk_display_manager.h"
#endif
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
@@ -75,6 +74,10 @@
#include "ui/wm/core/ime_util_chromeos.h"
#endif
+#if defined(OS_MACOSX)
+#include "ui/base/cocoa/secure_password_input.h"
+#endif
+
namespace views {
namespace {
@@ -262,6 +265,7 @@ Textfield::Textfield()
scheduled_text_edit_command_(ui::TextEditCommand::INVALID_COMMAND),
read_only_(false),
default_width_in_chars_(0),
+ minimum_width_in_chars_(-1),
use_default_text_color_(true),
use_default_background_color_(true),
use_default_selection_text_color_(true),
@@ -319,9 +323,16 @@ Textfield::~Textfield() {
}
}
-void Textfield::SetAssociatedLabel(Label* label) {
- label_ax_id_ = label->GetViewAccessibility().GetUniqueId().Get();
- accessible_name_ = label->text();
+void Textfield::SetAssociatedLabel(View* labelling_view) {
+ DCHECK(labelling_view);
+ label_ax_id_ = labelling_view->GetViewAccessibility().GetUniqueId().Get();
+ ui::AXNodeData node_data;
+ labelling_view->GetAccessibleNodeData(&node_data);
+ // TODO(aleventhal) automatically handle setting the name from the related
+ // label in view_accessibility and have it update the name if the text of the
+ // associated label changes.
+ SetAccessibleName(
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
}
void Textfield::SetReadOnly(bool read_only) {
@@ -502,6 +513,16 @@ void Textfield::SetFontList(const gfx::FontList& font_list) {
PreferredSizeChanged();
}
+void Textfield::SetDefaultWidthInChars(int default_width) {
+ DCHECK_GE(default_width, 0);
+ default_width_in_chars_ = default_width;
+}
+
+void Textfield::SetMinimumWidthInChars(int minimum_width) {
+ DCHECK_GE(minimum_width, -1);
+ minimum_width_in_chars_ = minimum_width;
+}
+
base::string16 Textfield::GetPlaceholderText() const {
return placeholder_text_;
}
@@ -515,7 +536,8 @@ void Textfield::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
}
void Textfield::ShowImeIfNeeded() {
- if (enabled() && !read_only())
+ // GetInputMethod() may return nullptr in tests.
+ if (enabled() && !read_only() && GetInputMethod())
GetInputMethod()->ShowImeIfNeeded();
}
@@ -601,14 +623,24 @@ int Textfield::GetBaseline() const {
}
gfx::Size Textfield::CalculatePreferredSize() const {
- const gfx::Insets& insets = GetInsets();
+ DCHECK_GE(default_width_in_chars_, minimum_width_in_chars_);
return gfx::Size(
GetFontList().GetExpectedTextWidth(default_width_in_chars_) +
- insets.width(),
+ GetInsets().width(),
LayoutProvider::GetControlHeightForFont(style::CONTEXT_TEXTFIELD,
GetTextStyle(), GetFontList()));
}
+gfx::Size Textfield::GetMinimumSize() const {
+ DCHECK_LE(minimum_width_in_chars_, default_width_in_chars_);
+ gfx::Size minimum_size = View::GetMinimumSize();
+ if (minimum_width_in_chars_ >= 0)
+ minimum_size.set_width(
+ GetFontList().GetExpectedTextWidth(minimum_width_in_chars_) +
+ GetInsets().width());
+ return minimum_size;
+}
+
const char* Textfield::GetClassName() const {
return kViewClassName;
}
@@ -1042,6 +1074,11 @@ void Textfield::OnPaint(gfx::Canvas* canvas) {
}
void Textfield::OnFocus() {
+#if defined(OS_MACOSX)
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
+ password_input_enabler_.reset(new ui::ScopedPasswordInputEnabler());
+#endif // defined(OS_MACOSX)
+
GetRenderText()->set_focused(true);
if (ShouldShowCursor()) {
UpdateCursorViewPosition();
@@ -1085,6 +1122,10 @@ void Textfield::OnBlur() {
FocusRing::Uninstall(this);
SchedulePaint();
View::OnBlur();
+
+#if defined(OS_MACOSX)
+ password_input_enabler_.reset();
+#endif // defined(OS_MACOSX)
}
gfx::Point Textfield::GetKeyboardContextMenuLocation() {
@@ -1183,11 +1224,18 @@ bool Textfield::CanStartDragForView(View* sender,
////////////////////////////////////////////////////////////////////////////////
// Textfield, WordLookupClient overrides:
-bool Textfield::GetDecoratedWordAtPoint(const gfx::Point& point,
- gfx::DecoratedText* decorated_word,
- gfx::Point* baseline_point) {
- return GetRenderText()->GetDecoratedWordAtPoint(point, decorated_word,
- baseline_point);
+bool Textfield::GetWordLookupDataAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) {
+ return GetRenderText()->GetWordLookupDataAtPoint(point, decorated_word,
+ baseline_point);
+}
+
+bool Textfield::GetWordLookupDataFromSelection(
+ gfx::DecoratedText* decorated_text,
+ gfx::Point* baseline_point) {
+ return GetRenderText()->GetLookupDataForRange(GetRenderText()->selection(),
+ decorated_text, baseline_point);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1284,10 +1332,20 @@ void Textfield::DestroyTouchSelection() {
// Textfield, ui::SimpleMenuModel::Delegate overrides:
bool Textfield::IsCommandIdChecked(int command_id) const {
+ if (text_services_context_menu_ &&
+ text_services_context_menu_->SupportsCommand(command_id)) {
+ return text_services_context_menu_->IsCommandIdChecked(command_id);
+ }
+
return true;
}
bool Textfield::IsCommandIdEnabled(int command_id) const {
+ if (text_services_context_menu_ &&
+ text_services_context_menu_->SupportsCommand(command_id)) {
+ return text_services_context_menu_->IsCommandIdEnabled(command_id);
+ }
+
return Textfield::IsTextEditCommandEnabled(
GetTextEditCommandFromMenuCommand(command_id, HasSelection()));
}
@@ -1315,12 +1373,27 @@ bool Textfield::GetAcceleratorForCommandId(int command_id,
*accelerator = ui::Accelerator(ui::VKEY_A, kPlatformModifier);
return true;
+ case IDS_CONTENT_CONTEXT_EMOJI:
+#if defined(OS_MACOSX)
+ *accelerator = ui::Accelerator(ui::VKEY_SPACE,
+ ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN);
+ return true;
+#else
+ return false;
+#endif
+
default:
return false;
}
}
void Textfield::ExecuteCommand(int command_id, int event_flags) {
+ if (text_services_context_menu_ &&
+ text_services_context_menu_->SupportsCommand(command_id)) {
+ text_services_context_menu_->ExecuteCommand(command_id);
+ return;
+ }
+
Textfield::ExecuteTextEditCommand(
GetTextEditCommandFromMenuCommand(command_id, HasSelection()));
}
@@ -2080,7 +2153,17 @@ void Textfield::OnCaretBoundsChanged() {
GetInputMethod()->OnCaretBoundsChanged(this);
if (touch_selection_controller_)
touch_selection_controller_->SelectionChanged();
- NotifyAccessibilityEvent(ax::mojom::Event::kTextSelectionChanged, true);
+
+#if defined(OS_MACOSX)
+ // On Mac, the context menu contains a look up item which displays the
+ // selected text. As such, the menu needs to be updated if the selection has
+ // changed.
+ context_menu_contents_.reset();
+#endif
+
+ // Screen reader users don't expect notifications about unfocused textfields.
+ if (HasFocus())
+ NotifyAccessibilityEvent(ax::mojom::Event::kTextSelectionChanged, true);
}
void Textfield::OnBeforeUserAction() {
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index db30abdd006..9c4b28d689f 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_type.h"
@@ -38,6 +39,12 @@ namespace base {
class TimeDelta;
}
+#if defined(OS_MACOSX)
+namespace ui {
+class ScopedPasswordInputEnabler;
+}
+#endif // defined(OS_MACOSX)
+
namespace views {
class Label;
@@ -83,8 +90,9 @@ class VIEWS_EXPORT Textfield : public View,
// features. The flags is the bit map of ui::TextInputFlags.
void SetTextInputFlags(int flags);
- // Gets the text for the Textfield. Call sites should take care to not reveal
- // the text for a password textfield.
+ // Gets the text for the Textfield.
+ // NOTE: Call sites should take care to not reveal the text for a password
+ // textfield.
const base::string16& text() const { return model_->text(); }
// Sets the text currently displayed in the Textfield. This doesn't
@@ -102,8 +110,9 @@ class VIEWS_EXPORT Textfield : public View,
// changes.
void InsertOrReplaceText(const base::string16& new_text);
- // Returns the text that is currently selected. Call sites should take care to
- // not reveal the text for a password textfield.
+ // Returns the text that is currently selected.
+ // NOTE: Call sites should take care to not reveal the text for a password
+ // textfield.
base::string16 GetSelectedText() const;
// Select the entire text range. If |reversed| is true, the range will end at
@@ -154,9 +163,10 @@ class VIEWS_EXPORT Textfield : public View,
void SetFontList(const gfx::FontList& font_list);
// Sets the default width of the text control. See default_width_in_chars_.
- void set_default_width_in_chars(int default_width) {
- default_width_in_chars_ = default_width;
- }
+ void SetDefaultWidthInChars(int default_width);
+
+ // Sets the minimum width of the text control. See minimum_width_in_chars_.
+ void SetMinimumWidthInChars(int minimum_width);
// Sets the text to display when empty.
void set_placeholder_text(const base::string16& text) {
@@ -224,10 +234,11 @@ class VIEWS_EXPORT Textfield : public View,
// label, use SetAssociatedLabel() instead.
void SetAccessibleName(const base::string16& name);
- // If the accessible name should be the same as the label text, use this. It
- // will set both the accessible label relationship and the accessible name
- // from the contents of the label.
- void SetAssociatedLabel(Label* label);
+ // If the accessible name should be the same as the labelling view's text,
+ // use this. It will set the accessible label relationship and copy the
+ // accessible name from the labelling views's accessible name. Any view with
+ // an accessible name can be used, typically a Label, StyledLabel or Link.
+ void SetAssociatedLabel(View* labelling_view);
// Set extra spacing placed between glyphs; used for obscured text styling.
void SetGlyphSpacing(int spacing);
@@ -235,6 +246,7 @@ class VIEWS_EXPORT Textfield : public View,
// View overrides:
int GetBaseline() const override;
gfx::Size CalculatePreferredSize() const override;
+ gfx::Size GetMinimumSize() const override;
const char* GetClassName() const override;
void SetBorder(std::unique_ptr<Border> b) override;
gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
@@ -287,9 +299,11 @@ class VIEWS_EXPORT Textfield : public View,
const gfx::Point& p) override;
// WordLookupClient overrides:
- bool GetDecoratedWordAtPoint(const gfx::Point& point,
- gfx::DecoratedText* decorated_word,
- gfx::Point* baseline_point) override;
+ bool GetWordLookupDataAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) override;
+ bool GetWordLookupDataFromSelection(gfx::DecoratedText* decorated_text,
+ gfx::Point* baseline_point) override;
// SelectionControllerDelegate overrides:
bool HasTextBeingDragged() const override;
@@ -483,9 +497,16 @@ class VIEWS_EXPORT Textfield : public View,
bool read_only_;
// The default number of average characters for the width of this text field.
- // This will be reported as the "desired size". Defaults to 0.
+ // This will be reported as the "desired size". Must be set to >=
+ // minimum_width_in_chars_. Defaults to 0.
int default_width_in_chars_;
+ // The minimum allowed width of this text field in average characters. This
+ // will be reported as the minimum size. Must be set to <=
+ // default_width_in_chars_. Setting this to -1 will cause GetMinimumSize() to
+ // return View::GetMinimumSize(). Defaults to -1.
+ int minimum_width_in_chars_;
+
// Flags indicating whether various system colors should be used, and if not,
// what overriding color values should be used instead.
bool use_default_text_color_;
@@ -575,6 +596,11 @@ class VIEWS_EXPORT Textfield : public View,
// View containing the text cursor.
View cursor_view_;
+#if defined(OS_MACOSX)
+ // Used to track active password input sessions.
+ std::unique_ptr<ui::ScopedPasswordInputEnabler> password_input_enabler_;
+#endif // defined(OS_MACOSX)
+
// Used to bind callback functions to this object.
base::WeakPtrFactory<Textfield> weak_ptr_factory_;
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index e06e12df73e..7b06af51838 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -16,6 +15,7 @@
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/utf16_indexing.h"
+#include "ui/views/style/platform_style.h"
namespace views {
@@ -258,7 +258,7 @@ namespace {
gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
for (size_t i = 0; i < composition.ime_text_spans.size(); ++i) {
const ui::ImeTextSpan& underline = composition.ime_text_spans[i];
- if (underline.thick)
+ if (underline.thickness == ui::ImeTextSpan::Thickness::kThick)
return gfx::Range(underline.start_offset, underline.end_offset);
}
return gfx::Range::InvalidRange();
@@ -406,10 +406,8 @@ bool TextfieldModel::Backspace(bool add_to_kill_buffer) {
}
size_t cursor_position = GetCursorPosition();
if (cursor_position > 0) {
- // Delete one code point, which may be two UTF-16 words.
- size_t previous_grapheme_index =
- gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
- gfx::Range range_to_delete(cursor_position, previous_grapheme_index);
+ gfx::Range range_to_delete(
+ PlatformStyle::RangeToDeleteBackwards(text(), cursor_position));
if (add_to_kill_buffer)
SetKillBuffer(GetTextFromRange(range_to_delete));
ExecuteAndRecordDelete(range_to_delete, true);
@@ -658,9 +656,10 @@ void TextfieldModel::SetCompositionText(
base::string16 new_text = text();
render_text_->SetText(new_text.insert(cursor, composition.text));
composition_range_ = gfx::Range(cursor, cursor + composition.text.length());
- // Don't render transparent IME spans.
+ // Don't render IME spans with thickness "kNone".
if (composition.ime_text_spans.size() > 0 &&
- composition.ime_text_spans[0].underline_color != 0)
+ composition.ime_text_spans[0].thickness !=
+ ui::ImeTextSpan::Thickness::kNone)
render_text_->SetCompositionRange(composition_range_);
else
render_text_->SetCompositionRange(gfx::Range::InvalidRange());
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index d35aba0f62a..c35b12260bf 100644
--- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -233,6 +233,38 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
EXPECT_TRUE(model.Backspace());
EXPECT_EQ(base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
model.text());
+
+ // Halfwidth katakana ダ:
+ // "HALFWIDTH KATAKANA LETTER TA" + "HALFWIDTH KATAKANA VOICED SOUND MARK"
+ // ("ABC" prefix as sanity check that the entire string isn't deleted).
+ model.SetText(base::WideToUTF16(L"ABC\xFF80\xFF9E"));
+ MoveCursorTo(model, model.text().length());
+ model.Backspace();
+#if defined(OS_MACOSX)
+ // On Mac, the entire cluster should be deleted to match
+ // NSTextField behavior.
+ EXPECT_EQ(base::WideToUTF16(L"ABC"), model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+#else
+ EXPECT_EQ(base::WideToUTF16(L"ABC\xFF80"), model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+#endif
+
+ // Emoji with Fitzpatrick modifier:
+ // 'BOY' + 'EMOJI MODIFIER FITZPATRICK TYPE-5'
+ model.SetText(base::WideToUTF16(L"\U0001F466\U0001F3FE"));
+ MoveCursorTo(model, model.text().length());
+ model.Backspace();
+#if defined(OS_MACOSX)
+ // On Mac, the entire emoji should be deleted to match NSTextField
+ // behavior.
+ EXPECT_EQ(base::WideToUTF16(L""), model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+#else
+ // https://crbug.com/829040
+ EXPECT_EQ(base::WideToUTF16(L"\U0001F466"), model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+#endif
}
TEST_F(TextfieldModelTest, EmptyString) {
@@ -973,7 +1005,8 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
ui::CompositionText composition;
composition.text = base::ASCIIToUTF16("678");
- composition.ime_text_spans.push_back(ui::ImeTextSpan(0, 3, 0, false));
+ composition.ime_text_spans.push_back(
+ ui::ImeTextSpan(0, 3, ui::ImeTextSpan::Thickness::kThin));
// Cursor should be at the end of composition when characters are just typed.
composition.selection = gfx::Range(3, 3);
@@ -988,8 +1021,10 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
// Restart composition with targeting "67" in "678".
composition.selection = gfx::Range(1, 3);
composition.ime_text_spans.clear();
- composition.ime_text_spans.push_back(ui::ImeTextSpan(0, 2, 0, true));
- composition.ime_text_spans.push_back(ui::ImeTextSpan(2, 3, 0, false));
+ composition.ime_text_spans.push_back(
+ ui::ImeTextSpan(0, 2, ui::ImeTextSpan::Thickness::kThick));
+ composition.ime_text_spans.push_back(
+ ui::ImeTextSpan(2, 3, ui::ImeTextSpan::Thickness::kThin));
model.SetCompositionText(composition);
EXPECT_TRUE(model.HasCompositionText());
EXPECT_TRUE(model.HasSelection());
@@ -1581,7 +1616,8 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
ui::CompositionText composition;
composition.text = base::ASCIIToUTF16("abc");
- composition.ime_text_spans.push_back(ui::ImeTextSpan(0, 3, 0, false));
+ composition.ime_text_spans.push_back(
+ ui::ImeTextSpan(0, 3, ui::ImeTextSpan::Thickness::kThin));
composition.selection = gfx::Range(2, 3);
model.SetText(base::ASCIIToUTF16("ABCDE"));
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 5cfb980672f..775c61fd31d 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -19,6 +19,7 @@
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/window.h"
@@ -30,6 +31,8 @@
#include "ui/base/ime/input_method_factory.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
@@ -67,6 +70,10 @@
#include "ui/wm/core/ime_util_chromeos.h"
#endif
+#if defined(OS_MACOSX)
+#include "ui/base/cocoa/secure_password_input.h"
+#endif
+
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
using base::WideToUTF16;
@@ -83,8 +90,6 @@ class MockInputMethod : public ui::InputMethodBase {
~MockInputMethod() override;
// Overridden from InputMethod:
- bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* key) override;
void OnTextInputTypeChanged(const ui::TextInputClient* client) override;
void OnCaretBoundsChanged(const ui::TextInputClient* client) override {}
@@ -144,13 +149,6 @@ MockInputMethod::MockInputMethod()
MockInputMethod::~MockInputMethod() {
}
-bool MockInputMethod::OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) {
- if (result)
- *result = NativeEventResult();
- return false;
-}
-
ui::EventDispatchDetails MockInputMethod::DispatchKeyEvent(ui::KeyEvent* key) {
// On Mac, emulate InputMethodMac behavior for character events. Composition
// still needs to be mocked, since it's not possible to generate test events
@@ -286,6 +284,15 @@ class TestTextfield : public views::Textfield {
event_flags_ = 0;
}
+ void OnAccessibilityEvent(ax::mojom::Event event_type) override {
+ if (event_type == ax::mojom::Event::kTextSelectionChanged)
+ ++accessibility_selection_fired_count_;
+ }
+
+ int GetAccessibilitySelectionFiredCount() {
+ return accessibility_selection_fired_count_;
+ }
+
private:
// views::View override:
void OnKeyEvent(ui::KeyEvent* event) override {
@@ -310,6 +317,7 @@ class TestTextfield : public views::Textfield {
bool key_handled_ = false;
bool key_received_ = false;
int event_flags_ = 0;
+ int accessibility_selection_fired_count_ = 0;
base::WeakPtrFactory<TestTextfield> weak_ptr_factory_{this};
@@ -688,21 +696,37 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
const bool is_all_selected = !text.empty() &&
textfield_->GetSelectedRange().length() == text.length();
- EXPECT_EQ(can_undo, menu->IsEnabledAt(0 /* UNDO */));
- EXPECT_TRUE(menu->IsEnabledAt(1 /* Separator */));
- EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(2 /* CUT */));
- EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(3 /* COPY */));
+ int menu_index = 0;
+#if defined(OS_MACOSX)
+ // On Mac, the Look Up item should appear at the top of the menu if the
+ // textfield has a selection.
+ if (textfield_has_selection) {
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* LOOK UP */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+ }
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* EMOJI */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+#endif
+
+ 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::CLIPBOARD_TYPE_COPY_PASTE).empty(),
- menu->IsEnabledAt(4 /* PASTE */));
- EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */));
- EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */));
- EXPECT_EQ(!is_all_selected, menu->IsEnabledAt(7 /* SELECT ALL */));
+ 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 */));
}
- void PressMouseButton(ui::EventFlags mouse_button_flags, int extra_flags) {
+ 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 | extra_flags);
+ mouse_button_flags);
textfield_->OnMousePressed(press);
}
@@ -713,21 +737,21 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
textfield_->OnMouseReleased(release);
}
- void PressLeftMouseButton(int extra_flags = 0) {
- PressMouseButton(ui::EF_LEFT_MOUSE_BUTTON, extra_flags);
+ void PressLeftMouseButton() {
+ PressMouseButton(ui::EF_LEFT_MOUSE_BUTTON);
}
void ReleaseLeftMouseButton() {
ReleaseMouseButton(ui::EF_LEFT_MOUSE_BUTTON);
}
- void ClickLeftMouseButton(int extra_flags = 0) {
- PressLeftMouseButton(extra_flags);
+ void ClickLeftMouseButton() {
+ PressLeftMouseButton();
ReleaseLeftMouseButton();
}
void ClickRightMouseButton() {
- PressMouseButton(ui::EF_RIGHT_MOUSE_BUTTON, 0);
+ PressMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
ReleaseMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
}
@@ -1516,6 +1540,9 @@ TEST_F(TextfieldTest, FocusTraversalTest) {
TEST_F(TextfieldTest, ContextMenuDisplayTest) {
InitTextfield();
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kEnableEmojiContextMenu);
+
EXPECT_TRUE(textfield_->context_menu_controller());
textfield_->SetText(ASCIIToUTF16("hello world"));
ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE);
@@ -1545,7 +1572,7 @@ TEST_F(TextfieldTest, DoubleAndTripleClickTest) {
MoveMouseTo(gfx::Point(0, GetCursorYForTesting()));
ClickLeftMouseButton();
EXPECT_TRUE(textfield_->GetSelectedText().empty());
- ClickLeftMouseButton(ui::EF_IS_DOUBLE_CLICK);
+ ClickLeftMouseButton();
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
// Test for triple click.
@@ -3436,6 +3463,93 @@ TEST_F(TextfieldTest, TextServicesContextMenuTextDirectionTest) {
EXPECT_TRUE(test_api_->IsTextDirectionCheckedInContextMenu(
base::i18n::TextDirection::RIGHT_TO_LEFT));
}
+
+// Tests to see if the look up item is updated when the textfield's selected
+// text has changed.
+TEST_F(TextfieldTest, LookUpItemUpdate) {
+ InitTextfield();
+ EXPECT_TRUE(textfield_->context_menu_controller());
+
+ const base::string16 kTextOne = ASCIIToUTF16("crake");
+ textfield_->SetText(kTextOne);
+ textfield_->SelectAll(false);
+
+ ui::MenuModel* context_menu = GetContextMenuModel();
+ EXPECT_TRUE(context_menu);
+ EXPECT_GT(context_menu->GetItemCount(), 0);
+ EXPECT_EQ(context_menu->GetLabelAt(0),
+ l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP, kTextOne));
+
+ const base::string16 kTextTwo = ASCIIToUTF16("rail");
+ textfield_->SetText(kTextTwo);
+ textfield_->SelectAll(false);
+
+ context_menu = GetContextMenuModel();
+ EXPECT_TRUE(context_menu);
+ EXPECT_GT(context_menu->GetItemCount(), 0);
+ EXPECT_EQ(context_menu->GetLabelAt(0),
+ l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP, kTextTwo));
+}
+
+// Tests to see if the look up item is hidden for password fields.
+TEST_F(TextfieldTest, LookUpPassword) {
+ InitTextfield();
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+
+ const base::string16 kText = ASCIIToUTF16("Willie Wagtail");
+
+ textfield_->SetText(kText);
+ textfield_->SelectAll(false);
+
+ ui::MenuModel* context_menu = GetContextMenuModel();
+ EXPECT_TRUE(context_menu);
+ EXPECT_GT(context_menu->GetItemCount(), 0);
+ EXPECT_NE(context_menu->GetCommandIdAt(0), IDS_CONTENT_CONTEXT_LOOK_UP);
+ EXPECT_NE(context_menu->GetLabelAt(0),
+ l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP, kText));
+}
+
+TEST_F(TextfieldTest, SecurePasswordInput) {
+ InitTextfield();
+ ASSERT_FALSE(ui::ScopedPasswordInputEnabler::IsPasswordInputEnabled());
+
+ // Shouldn't enable secure input if it's not a password textfield.
+ textfield_->OnFocus();
+ EXPECT_FALSE(ui::ScopedPasswordInputEnabler::IsPasswordInputEnabled());
+
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+
+ // Single matched calls immediately update IsPasswordInputEnabled().
+ textfield_->OnFocus();
+ EXPECT_TRUE(ui::ScopedPasswordInputEnabler::IsPasswordInputEnabled());
+
+ textfield_->OnBlur();
+ EXPECT_FALSE(ui::ScopedPasswordInputEnabler::IsPasswordInputEnabled());
+}
#endif // defined(OS_MACOSX)
+TEST_F(TextfieldTest, AccessibilitySelectionEvents) {
+ const std::string& kText = "abcdef";
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16(kText));
+ EXPECT_TRUE(textfield_->HasFocus());
+ int previous_selection_fired_count =
+ textfield_->GetAccessibilitySelectionFiredCount();
+ textfield_->SelectAll(false);
+ EXPECT_LT(previous_selection_fired_count,
+ textfield_->GetAccessibilitySelectionFiredCount());
+ previous_selection_fired_count =
+ textfield_->GetAccessibilitySelectionFiredCount();
+
+ // No selection event when textfield blurred, even though text is
+ // deselected.
+ widget_->GetFocusManager()->ClearFocus();
+ EXPECT_FALSE(textfield_->HasFocus());
+ textfield_->ClearSelection();
+ EXPECT_FALSE(textfield_->HasSelection());
+ // Has not changed.
+ EXPECT_EQ(previous_selection_fired_count,
+ textfield_->GetAccessibilitySelectionFiredCount());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index f5709270c99..4b8d78b239a 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/i18n/rtl.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "build/build_config.h"
#include "components/vector_icons/vector_icons.h"
@@ -427,8 +426,16 @@ void TreeView::ShowContextMenu(const gfx::Point& p,
void TreeView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kTree;
node_data->SetRestriction(ax::mojom::Restriction::kReadOnly);
- if (!selected_node_)
+ // TODO(aleventhal): The tree view accessibility implementation is misusing
+ // the name field. It should really be using selection events for the
+ // currently selected item. The name field should be for for the label
+ // if there is one, otherwise something that would work in place of a label.
+ // See http://crbug.com/811277.
+
+ if (!selected_node_) {
+ node_data->SetNameExplicitlyEmpty();
return;
+ }
// Get selected item info.
node_data->role = ax::mojom::Role::kTreeItem;
diff --git a/chromium/ui/views/controls/tree/tree_view_unittest.cc b/chromium/ui/views/controls/tree/tree_view_unittest.cc
index 02d3ef1c246..fa4c7bf7b0c 100644
--- a/chromium/ui/views/controls/tree/tree_view_unittest.cc
+++ b/chromium/ui/views/controls/tree/tree_view_unittest.cc
@@ -7,7 +7,6 @@
#include <string>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/models/tree_node_model.h"
diff --git a/chromium/ui/views/controls/views_text_services_context_menu.h b/chromium/ui/views/controls/views_text_services_context_menu.h
index 2388b27653b..bf411354261 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu.h
+++ b/chromium/ui/views/controls/views_text_services_context_menu.h
@@ -34,6 +34,14 @@ class ViewsTextServicesContextMenu {
VIEWS_EXPORT static bool IsTextDirectionCheckedForTesting(
ViewsTextServicesContextMenu* menu,
base::i18n::TextDirection direction);
+
+ // Returns true if the given |command_id| is handled by the menu.
+ virtual bool SupportsCommand(int command_id) const = 0;
+
+ // Methods associated with SimpleMenuModel::Delegate.
+ virtual bool IsCommandIdChecked(int command_id) const = 0;
+ virtual bool IsCommandIdEnabled(int command_id) const = 0;
+ virtual void ExecuteCommand(int command_id) = 0;
};
} // namespace views
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_mac.mm b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
index be96d8ac4ee..0c4cd260bed 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
+++ b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
@@ -4,10 +4,21 @@
#include "ui/views/controls/views_text_services_context_menu.h"
-#include "base/memory/ptr_util.h"
+#import <Cocoa/Cocoa.h>
+
+#include "base/feature_list.h"
#include "ui/base/cocoa/text_services_context_menu.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/gfx/decorated_text.h"
+#import "ui/gfx/decorated_text_mac.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
namespace views {
@@ -16,21 +27,78 @@ namespace {
// This class serves as a bridge to TextServicesContextMenu to add and handle
// text service items in the context menu. The items include Speech, Look Up
// and BiDi.
-// TODO (spqchan): Add Look Up and BiDi.
class ViewsTextServicesContextMenuMac
: public ViewsTextServicesContextMenu,
public ui::TextServicesContextMenu::Delegate {
public:
ViewsTextServicesContextMenuMac(ui::SimpleMenuModel* menu, Textfield* client)
: text_services_menu_(this), client_(client) {
+ // The index to use when inserting items into the menu.
+ int index = 0;
+
+ base::string16 text = GetSelectedText();
+ if (!text.empty()) {
+ menu->InsertItemAt(
+ index++, IDS_CONTENT_CONTEXT_LOOK_UP,
+ l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP, text));
+ menu->InsertSeparatorAt(index++, ui::NORMAL_SEPARATOR);
+ }
+ if (base::FeatureList::IsEnabled(features::kEnableEmojiContextMenu)) {
+ menu->InsertItemWithStringIdAt(index++, IDS_CONTENT_CONTEXT_EMOJI,
+ IDS_CONTENT_CONTEXT_EMOJI);
+ menu->InsertSeparatorAt(index++, ui::NORMAL_SEPARATOR);
+ }
text_services_menu_.AppendToContextMenu(menu);
text_services_menu_.AppendEditableItems(menu);
}
~ViewsTextServicesContextMenuMac() override {}
+ // ViewsTextServicesContextMenu:
+ bool SupportsCommand(int command_id) const override {
+ return text_services_menu_.SupportsCommand(command_id) ||
+ command_id == IDS_CONTENT_CONTEXT_EMOJI ||
+ command_id == IDS_CONTENT_CONTEXT_LOOK_UP;
+ }
+
+ bool IsCommandIdChecked(int command_id) const override {
+ DCHECK_EQ(IDS_CONTENT_CONTEXT_LOOK_UP, command_id);
+ return false;
+ }
+
+ bool IsCommandIdEnabled(int command_id) const override {
+ if (text_services_menu_.SupportsCommand(command_id))
+ return text_services_menu_.IsCommandIdEnabled(command_id);
+
+ switch (command_id) {
+ case IDS_CONTENT_CONTEXT_EMOJI:
+ return true;
+
+ case IDS_CONTENT_CONTEXT_LOOK_UP:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ void ExecuteCommand(int command_id) override {
+ switch (command_id) {
+ case IDS_CONTENT_CONTEXT_EMOJI:
+ [NSApp orderFrontCharacterPalette:nil];
+ break;
+
+ case IDS_CONTENT_CONTEXT_LOOK_UP:
+ LookUpInDictionary();
+ break;
+ }
+ }
+
// TextServicesContextMenu::Delegate:
base::string16 GetSelectedText() const override {
+ if (client_->GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD)
+ return base::string16();
+
return client_->GetSelectedText();
}
@@ -55,6 +123,24 @@ class ViewsTextServicesContextMenuMac
}
private:
+ // Handler for the "Look Up" menu item.
+ void LookUpInDictionary() {
+ gfx::Point baseline_point;
+ gfx::DecoratedText text;
+ if (client_->GetWordLookupDataFromSelection(&text, &baseline_point)) {
+ Widget* widget = client_->GetWidget();
+ gfx::NativeView view = widget->GetNativeView();
+ views::View::ConvertPointToTarget(client_, widget->GetRootView(),
+ &baseline_point);
+
+ NSPoint lookup_point = NSMakePoint(
+ baseline_point.x(), NSHeight([view frame]) - baseline_point.y());
+ [view showDefinitionForAttributedString:
+ gfx::GetAttributedStringFromDecoratedText(text)
+ atPoint:lookup_point];
+ }
+ }
+
// Appends and handles the text service menu.
ui::TextServicesContextMenu text_services_menu_;
@@ -80,4 +166,4 @@ bool ViewsTextServicesContextMenu::IsTextDirectionCheckedForTesting(
return static_cast<views::ViewsTextServicesContextMenuMac*>(menu)
->IsTextDirectionChecked(direction);
}
-} // namespace views \ No newline at end of file
+} // namespace views
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index ba3480d6440..ef8b793f745 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -28,7 +28,7 @@ using content::NativeWebKeyboardEvent;
using content::WebContents;
using content::WebUIMessageHandler;
using ui::WebDialogDelegate;
-using ui::WebDialogUI;
+using ui::WebDialogUIBase;
using ui::WebDialogWebContentsDelegate;
namespace views {
@@ -365,7 +365,7 @@ void WebDialogView::InitDialog() {
// Set the delegate. This must be done before loading the page. See
// the comment above WebDialogUI in its header file for why.
- WebDialogUI::SetDelegate(web_contents, this);
+ WebDialogUIBase::SetDelegate(web_contents, this);
web_view_->LoadInitialURL(GetDialogContentURL());
}
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index 5144b14e415..4ec50f3b056 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -147,6 +147,10 @@ void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
// Reset the native view size.
holder_->SetNativeViewSize(gfx::Size());
holder_->SetBoundsRect(holder_bounds);
+ if (is_letterboxing_) {
+ is_letterboxing_ = false;
+ OnLetterboxingChanged();
+ }
return;
}
@@ -165,6 +169,10 @@ void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
static_cast<int>(x / capture_size.height()), holder_bounds.height()));
}
+ if (!is_letterboxing_) {
+ is_letterboxing_ = true;
+ OnLetterboxingChanged();
+ }
holder_->SetNativeViewSize(capture_size);
holder_->SetBoundsRect(holder_bounds);
}
diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h
index afdd0a03938..99affc147bc 100644
--- a/chromium/ui/views/controls/webview/webview.h
+++ b/chromium/ui/views/controls/webview/webview.h
@@ -103,6 +103,10 @@ class WEBVIEW_EXPORT WebView : public View,
// Called when the web contents is successfully attached.
virtual void OnWebContentsAttached() {}
+ // Called when letterboxing (scaling the native view to preserve aspect
+ // ratio) is enabled or disabled.
+ virtual void OnLetterboxingChanged() {}
+ bool is_letterboxing() const { return is_letterboxing_; }
// Overridden from View:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
@@ -162,6 +166,9 @@ class WEBVIEW_EXPORT WebView : public View,
// view instead of the normal WebContentsView render view. Note: This will be
// false in the case of non-Flash fullscreen.
bool is_embedding_fullscreen_widget_;
+ // Set to true when |holder_| is letterboxed (scaled to be smaller than this
+ // view, to preserve its aspect ratio).
+ bool is_letterboxing_ = false;
content::BrowserContext* browser_context_;
bool allow_accelerators_;
View* crashed_overlay_view_ = nullptr;
diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc
index b3c86732c50..b679af9d8d2 100644
--- a/chromium/ui/views/controls/webview/webview_unittest.cc
+++ b/chromium/ui/views/controls/webview/webview_unittest.cc
@@ -8,10 +8,13 @@
#include <memory>
+#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/web_contents_tester.h"
@@ -151,6 +154,9 @@ class WebViewUnitTest : public views::test::WidgetTest {
// dependencies from content.
SetBrowserClientForTesting(&test_browser_client_);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisableBackgroundingOccludedWindowsForTesting);
+
// Create a top level widget and add a child, and give it a WebView as a
// child.
top_level_widget_ = CreateTopLevelFramelessPlatformWidget();
@@ -186,6 +192,10 @@ class WebViewUnitTest : public views::test::WidgetTest {
}
private:
+ // TODO(lukasza): https://crbug.com/832100: Move the factory into
+ // TestingProfile, so individual tests don't need to worry about it.
+ content::ScopedMockRenderProcessHostFactory process_factory_;
+
content::TestBrowserThreadBundle test_browser_thread_bundle_;
std::unique_ptr<content::TestBrowserContext> browser_context_;
content::TestContentBrowserClient test_browser_client_;
diff --git a/chromium/ui/views/examples/box_layout_example.cc b/chromium/ui/views/examples/box_layout_example.cc
index ef7c9146f57..2c4fba15fb2 100644
--- a/chromium/ui/views/examples/box_layout_example.cc
+++ b/chromium/ui/views/examples/box_layout_example.cc
@@ -6,7 +6,6 @@
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -193,7 +192,7 @@ void ChildPanel::ContentsChanged(Textfield* sender,
Textfield* ChildPanel::CreateTextfield() {
Textfield* textfield = new Textfield();
- textfield->set_default_width_in_chars(3);
+ textfield->SetDefaultWidthInChars(3);
textfield->SizeToPreferredSize();
textfield->SetText(base::ASCIIToUTF16("0"));
textfield->set_controller(this);
@@ -242,7 +241,7 @@ Textfield* BoxLayoutExample::CreateRawTextfield(int& horizontal_pos,
bool add) {
Textfield* text_field = new Textfield();
text_field->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
- text_field->set_default_width_in_chars(3);
+ text_field->SetDefaultWidthInChars(3);
text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
text_field->SizeToPreferredSize();
text_field->SetText(base::ASCIIToUTF16("0"));
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index 807ba934af9..dd63355096e 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -67,10 +67,12 @@ int main(int argc, char** argv) {
gl::init::InitializeGLOneOff();
// The ContextFactory must exist before any Compositors are created.
- viz::HostFrameSinkManager host_frame_sink_manager_;
- viz::FrameSinkManagerImpl frame_sink_manager_;
+ viz::HostFrameSinkManager host_frame_sink_manager;
+ viz::FrameSinkManagerImpl frame_sink_manager;
+ host_frame_sink_manager.SetLocalManager(&frame_sink_manager);
+ frame_sink_manager.SetLocalClient(&host_frame_sink_manager);
auto context_factory = std::make_unique<ui::InProcessContextFactory>(
- &host_frame_sink_manager_, &frame_sink_manager_);
+ &host_frame_sink_manager, &frame_sink_manager);
context_factory->set_use_test_surface(false);
base::test::ScopedTaskEnvironment scoped_task_environment(
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index e6b46660e7c..b903e478740 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -10,7 +10,6 @@
#include <utility>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chromium/ui/views/examples/examples_window_with_content.cc b/chromium/ui/views/examples/examples_window_with_content.cc
index bf87c71eac8..1133e88fa9a 100644
--- a/chromium/ui/views/examples/examples_window_with_content.cc
+++ b/chromium/ui/views/examples/examples_window_with_content.cc
@@ -8,7 +8,6 @@
#include <utility>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "content/public/browser/browser_context.h"
#include "ui/views/examples/webview_example.h"
diff --git a/chromium/ui/views/examples/text_example.cc b/chromium/ui/views/examples/text_example.cc
index 8b95cf23acb..17439cc8bc6 100644
--- a/chromium/ui/views/examples/text_example.cc
+++ b/chromium/ui/views/examples/text_example.cc
@@ -5,7 +5,6 @@
#include "ui/views/examples/text_example.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
diff --git a/chromium/ui/views/examples/tree_view_example.cc b/chromium/ui/views/examples/tree_view_example.cc
index c6621eb3911..6626f709a97 100644
--- a/chromium/ui/views/examples/tree_view_example.cc
+++ b/chromium/ui/views/examples/tree_view_example.cc
@@ -4,7 +4,6 @@
#include "ui/views/examples/tree_view_example.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
diff --git a/chromium/ui/views/focus/external_focus_tracker.cc b/chromium/ui/views/focus/external_focus_tracker.cc
index 280f09f8ae3..b843dc20795 100644
--- a/chromium/ui/views/focus/external_focus_tracker.cc
+++ b/chromium/ui/views/focus/external_focus_tracker.cc
@@ -5,7 +5,6 @@
#include "ui/views/focus/external_focus_tracker.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/views/view.h"
#include "ui/views/view_tracker.h"
diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc
index c3c5e4c74f8..fb3b9016097 100644
--- a/chromium/ui/views/focus/focus_manager.cc
+++ b/chromium/ui/views/focus/focus_manager.cc
@@ -10,7 +10,6 @@
#include "base/auto_reset.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
diff --git a/chromium/ui/views/focus/focus_manager_factory.cc b/chromium/ui/views/focus/focus_manager_factory.cc
index 85c5e49e462..5ebe513b2e3 100644
--- a/chromium/ui/views/focus/focus_manager_factory.cc
+++ b/chromium/ui/views/focus/focus_manager_factory.cc
@@ -4,7 +4,6 @@
#include "ui/views/focus/focus_manager_factory.h"
-#include "base/memory/ptr_util.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/focus_manager_delegate.h"
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index ff55f0a3bc5..809b6d8a3ac 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -11,7 +11,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
#include "ui/base/accelerators/accelerator.h"
diff --git a/chromium/ui/views/focus/focus_traversal_unittest.cc b/chromium/ui/views/focus/focus_traversal_unittest.cc
index 5085a704180..2e45e0ab16d 100644
--- a/chromium/ui/views/focus/focus_traversal_unittest.cc
+++ b/chromium/ui/views/focus/focus_traversal_unittest.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/ui/views/layout/box_layout.cc b/chromium/ui/views/layout/box_layout.cc
index fabf5bb492e..d0d5624bf24 100644
--- a/chromium/ui/views/layout/box_layout.cc
+++ b/chromium/ui/views/layout/box_layout.cc
@@ -106,12 +106,15 @@ BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
BoxLayout::~BoxLayout() {
}
-void BoxLayout::SetFlexForView(const View* view, int flex_weight) {
+void BoxLayout::SetFlexForView(const View* view,
+ int flex_weight,
+ bool use_min_size) {
DCHECK(host_);
DCHECK(view);
DCHECK_EQ(host_, view->parent());
DCHECK_GE(flex_weight, 0);
- flex_map_[view] = flex_weight;
+ flex_map_[view].flex_weight = flex_weight;
+ flex_map_[view].use_min_size = use_min_size;
}
void BoxLayout::ClearFlexForView(const View* view) {
@@ -250,8 +253,9 @@ void BoxLayout::Layout(View* host) {
// Calculate flex padding.
int current_padding = 0;
- if (GetFlexForView(child.view()) > 0) {
- current_flex += GetFlexForView(child.view());
+ int child_flex = GetFlexForView(child.view());
+ if (child_flex > 0) {
+ current_flex += child_flex;
int quot = (main_free_space * current_flex) / flex_sum;
int rem = (main_free_space * current_flex) % flex_sum;
current_padding = quot - total_padding;
@@ -265,7 +269,12 @@ void BoxLayout::Layout(View* host) {
// TODO(bruthig): Use the allocated width to determine the cross axis size.
// See https://crbug.com/682266.
int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
- SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
+ int child_min_size = GetMinimumSizeForView(child.view());
+ if (child_min_size > 0 && !collapse_margins_spacing_)
+ child_min_size += child.margins().width();
+ SetMainAxisSize(
+ std::max(child_min_size, child_main_axis_size + current_padding),
+ &bounds);
if (MainAxisSize(bounds) > 0 || GetFlexForView(child.view()) > 0)
main_position += MainAxisSize(bounds) +
MainAxisMarginBetweenViews(
@@ -359,7 +368,16 @@ int BoxLayout::GetFlexForView(const View* view) const {
if (it == flex_map_.end())
return default_flex_;
- return it->second;
+ return it->second.flex_weight;
+}
+
+int BoxLayout::GetMinimumSizeForView(const View* view) const {
+ FlexMap::const_iterator it = flex_map_.find(view);
+ if (it == flex_map_.end() || !it->second.use_min_size)
+ return 0;
+
+ return (orientation_ == kHorizontal) ? view->GetMinimumSize().width()
+ : view->GetMinimumSize().height();
}
int BoxLayout::MainAxisSize(const gfx::Rect& rect) const {
diff --git a/chromium/ui/views/layout/box_layout.h b/chromium/ui/views/layout/box_layout.h
index c2bf8901341..315ac561859 100644
--- a/chromium/ui/views/layout/box_layout.h
+++ b/chromium/ui/views/layout/box_layout.h
@@ -132,10 +132,15 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
// the basis, free space along the main axis is distributed to views in the
// ratio of their flex weights. Similarly, if the views will overflow the
// parent, space is subtracted in these ratios.
+ // If true is passed in for |use_min_size|, the given view's minimum size
+ // is then obtained from calling View::GetMinimumSize(). This will be the
+ // minimum allowed size for the view along the main axis. False
+ // for |use_min_size| (the default) will allow the |view| to be resized to a
+ // minimum size of 0.
//
// A flex of 0 means this view is not resized. Flex values must not be
// negative.
- void SetFlexForView(const View* view, int flex);
+ void SetFlexForView(const View* view, int flex, bool use_min_size = false);
// Clears the flex for the given |view|, causing it to use the default
// flex.
@@ -187,11 +192,19 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
DISALLOW_COPY_AND_ASSIGN(ViewWrapper);
};
- using FlexMap = std::map<const View*, int>;
+ struct Flex {
+ int flex_weight;
+ bool use_min_size;
+ };
+
+ using FlexMap = std::map<const View*, Flex>;
// Returns the flex for the specified |view|.
int GetFlexForView(const View* view) const;
+ // Returns the minimum size for the specified |view|.
+ int GetMinimumSizeForView(const View* view) const;
+
// Returns the size and position along the main axis of |rect|.
int MainAxisSize(const gfx::Rect& rect) const;
int MainAxisPosition(const gfx::Rect& rect) const;
diff --git a/chromium/ui/views/layout/box_layout_unittest.cc b/chromium/ui/views/layout/box_layout_unittest.cc
index 8d46a6f15d7..676109da968 100644
--- a/chromium/ui/views/layout/box_layout_unittest.cc
+++ b/chromium/ui/views/layout/box_layout_unittest.cc
@@ -884,4 +884,31 @@ TEST_F(BoxLayoutTest, NegativeBetweenChildSpacing) {
EXPECT_EQ(gfx::Rect(0, 10, 20, 15), v2->bounds());
}
+TEST_F(BoxLayoutTest, MinimumChildSize) {
+ BoxLayout* layout = host_->SetLayoutManager(
+ std::make_unique<BoxLayout>(BoxLayout::kHorizontal, gfx::Insets()));
+ StaticSizedView* v1 = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(v1);
+ StaticSizedView* v2 = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(v2);
+
+ v1->set_minimum_size(gfx::Size(10, 20));
+ layout->SetFlexForView(v1, 1, true);
+
+ gfx::Size preferred_size = layout->GetPreferredSize(host_.get());
+ EXPECT_EQ(40, preferred_size.width());
+ EXPECT_EQ(20, preferred_size.height());
+
+ host_->SetBounds(0, 0, 15, 20);
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 20), v1->bounds());
+ EXPECT_EQ(gfx::Rect(10, 0, 5, 20), v2->bounds());
+
+ v1->set_minimum_size(gfx::Size(5, 20));
+
+ host_->Layout();
+ EXPECT_EQ(gfx::Rect(0, 0, 5, 20), v1->bounds());
+ EXPECT_EQ(gfx::Rect(5, 0, 10, 20), v2->bounds());
+}
+
} // namespace views
diff --git a/chromium/ui/views/layout/layout_provider.cc b/chromium/ui/views/layout/layout_provider.cc
index 44f3dedac84..1902f4ff539 100644
--- a/chromium/ui/views/layout/layout_provider.cc
+++ b/chromium/ui/views/layout/layout_provider.cc
@@ -5,7 +5,6 @@
#include "ui/views/layout/layout_provider.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/font_list.h"
#include "ui/views/style/typography.h"
@@ -43,6 +42,7 @@ int LayoutProvider::GetControlHeightForFont(int context,
}
gfx::Insets LayoutProvider::GetInsetsMetric(int metric) const {
+ DCHECK_GE(metric, VIEWS_INSETS_START);
DCHECK_LT(metric, VIEWS_INSETS_MAX);
switch (metric) {
case InsetsMetric::INSETS_DIALOG:
@@ -58,17 +58,22 @@ gfx::Insets LayoutProvider::GetInsetsMetric(int metric) const {
return gfx::Insets(dialog_insets.top(), dialog_insets.left(), 0,
dialog_insets.right());
}
+ case InsetsMetric::INSETS_TOOLTIP_BUBBLE:
+ return gfx::Insets(8);
case InsetsMetric::INSETS_CHECKBOX_RADIO_BUTTON:
return gfx::Insets(5, 6);
case InsetsMetric::INSETS_VECTOR_IMAGE_BUTTON:
return gfx::Insets(4);
+ case InsetsMetric::INSETS_LABEL_BUTTON:
+ return gfx::Insets(5, 6);
}
NOTREACHED();
return gfx::Insets();
}
int LayoutProvider::GetDistanceMetric(int metric) const {
- DCHECK_GE(metric, VIEWS_INSETS_MAX);
+ DCHECK_GE(metric, VIEWS_DISTANCE_START);
+ DCHECK_LT(metric, VIEWS_DISTANCE_MAX);
switch (metric) {
case DistanceMetric::DISTANCE_BUTTON_HORIZONTAL_PADDING:
return 16;
diff --git a/chromium/ui/views/layout/layout_provider.h b/chromium/ui/views/layout/layout_provider.h
index d67ed3ba617..991b8e51681 100644
--- a/chromium/ui/views/layout/layout_provider.h
+++ b/chromium/ui/views/layout/layout_provider.h
@@ -32,9 +32,13 @@ enum InsetsMetric {
// The margins around the icon/title of a dialog. The bottom margin is implied
// by the content insets and the other margins overlap with INSETS_DIALOG.
INSETS_DIALOG_TITLE,
+ // The margins around the edges of a tooltip bubble.
+ INSETS_TOOLTIP_BUBBLE,
// Padding to add to vector image buttons to increase their click and touch
// target size.
INSETS_VECTOR_IMAGE_BUTTON,
+ // Padding used in a label button.
+ INSETS_LABEL_BUTTON,
// Embedders must start Insets enum values from this value.
VIEWS_INSETS_END,
@@ -96,7 +100,10 @@ enum DistanceMetric {
DISTANCE_UNRELATED_CONTROL_VERTICAL,
// Embedders must start DistanceMetric enum values from here.
- VIEWS_DISTANCE_END
+ VIEWS_DISTANCE_END,
+
+ // All Distance enum values must be below this value.
+ VIEWS_DISTANCE_MAX = 0x2000
};
// The type of a dialog content element. TEXT should be used for Labels or other
diff --git a/chromium/ui/views/linux_ui/OWNERS b/chromium/ui/views/linux_ui/OWNERS
index 4733a4f06bf..280ba478dca 100644
--- a/chromium/ui/views/linux_ui/OWNERS
+++ b/chromium/ui/views/linux_ui/OWNERS
@@ -1 +1 @@
-erg@chromium.org
+thomasanderson@chromium.org
diff --git a/chromium/ui/views/mouse_watcher.cc b/chromium/ui/views/mouse_watcher.cc
index 0f56dcef318..e0c1a3bb44b 100644
--- a/chromium/ui/views/mouse_watcher.cc
+++ b/chromium/ui/views/mouse_watcher.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/event_types.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -16,6 +15,7 @@
#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_utils.h"
+#include "ui/events/platform_event.h"
#include "ui/views/event_monitor.h"
namespace views {
@@ -64,8 +64,9 @@ class MouseWatcher::Observer : public ui::EventHandler {
// Mouse moved outside the host's zone, start a timer to notify the
// listener.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&Observer::NotifyListener,
- notify_listener_factory_.GetWeakPtr()),
+ FROM_HERE,
+ base::BindOnce(&Observer::NotifyListener,
+ notify_listener_factory_.GetWeakPtr()),
event_type == MouseWatcherHost::MOUSE_MOVE
? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)
: mouse_watcher_->notify_on_exit_time_);
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index a8e4c997153..dfe239c16d5 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -80,9 +80,9 @@ jumbo_component("mus") {
]
if (is_linux && !is_android) {
- deps += [ "//components/font_service/public/cpp" ]
+ deps += [ "//components/services/font/public/cpp" ]
data_deps = [
- "//components/font_service",
+ "//components/services/font:font_service",
]
}
}
@@ -122,7 +122,7 @@ jumbo_static_library("test_support") {
":mus",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//services/catalog:lib",
"//services/service_manager/background:lib",
"//services/service_manager/public/cpp",
@@ -192,6 +192,7 @@ test("views_mus_unittests") {
"//ui/views",
"//ui/views:test_support_internal",
"//ui/views:views_unittests_sources",
+ "//ui/views/mus/remote_view:tests",
"//ui/wm",
"//url",
]
@@ -244,7 +245,7 @@ test("views_mus_interactive_ui_tests") {
":mus",
":test_support",
"//base",
- "//mojo/edk/system",
+ "//mojo/edk",
"//testing/gmock",
"//testing/gtest",
"//ui/aura",
diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS
index 4d8a1fd285a..21ea014c764 100644
--- a/chromium/ui/views/mus/DEPS
+++ b/chromium/ui/views/mus/DEPS
@@ -1,7 +1,7 @@
include_rules = [
"+cc",
"-cc/blink",
- "+components/font_service/public",
+ "+components/services/font/public",
"+components/gpu",
"+mojo/cc",
"+mojo/common",
diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc
index 7631ab57b0e..ea6490d4ec3 100644
--- a/chromium/ui/views/mus/aura_init.cc
+++ b/chromium/ui/views/mus/aura_init.cc
@@ -25,7 +25,7 @@
#include "ui/views/views_delegate.h"
#if defined(OS_LINUX)
-#include "components/font_service/public/cpp/font_loader.h"
+#include "components/services/font/public/cpp/font_loader.h"
#include "ui/gfx/platform_font_linux.h"
#endif
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
index b24db3fc938..c417e738573 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -4,7 +4,6 @@
#include "ui/views/mus/desktop_window_tree_host_mus.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/aura/client/aura_constants.h"
@@ -211,7 +210,7 @@ DesktopWindowTreeHostMus::DesktopWindowTreeHostMus(
MusClient::Get()->AddObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->AddObserver(
this);
- desktop_native_widget_aura_->content_window()->AddObserver(this);
+ content_window()->AddObserver(this);
// DesktopNativeWidgetAura registers the association between |content_window_|
// and Widget, but code may also want to go from the root (window()) to the
// Widget. This call enables that.
@@ -226,7 +225,7 @@ DesktopWindowTreeHostMus::~DesktopWindowTreeHostMus() {
// the cursor-client needs to be unset on the root-window before
// |cursor_manager_| is destroyed.
aura::client::SetCursorClient(window(), nullptr);
- desktop_native_widget_aura_->content_window()->RemoveObserver(this);
+ content_window()->RemoveObserver(this);
MusClient::Get()->RemoveObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->RemoveObserver(
this);
@@ -293,8 +292,7 @@ bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL;
}
-void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
- const Widget::InitParams& params) {
+void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
// |TYPE_WINDOW| and |TYPE_PANEL| are forced to transparent as otherwise the
// window is opaque and the client decorations drawn by the window manager
// would not be seen.
@@ -302,7 +300,7 @@ void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW ||
params.type == Widget::InitParams::TYPE_WINDOW ||
params.type == Widget::InitParams::TYPE_PANEL;
- content_window->SetTransparent(transparent);
+ content_window()->SetTransparent(transparent);
window()->SetTransparent(transparent);
window()->SetProperty(aura::client::kShowStateKey, params.show_state);
@@ -325,18 +323,14 @@ void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
params.parent->GetHost()->window(), window());
}
- if (!params.accept_events) {
+ if (!params.accept_events)
window()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::NONE);
- } else {
- aura::WindowPortMus::Get(content_window)->SetCanAcceptDrops(true);
- }
+ else
+ aura::WindowPortMus::Get(content_window())->SetCanAcceptDrops(true);
}
void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
const Widget::InitParams& params) {
- window()->SetName(params.name);
- desktop_native_widget_aura_->content_window()->SetName(
- "DesktopNativeWidgetAura - content window");
if (params.parent && params.parent->GetHost()) {
parent_ = static_cast<DesktopWindowTreeHostMus*>(params.parent->GetHost());
parent_->children_.insert(this);
@@ -396,8 +390,8 @@ void DesktopWindowTreeHostMus::Close() {
// Close doesn't delete this immediately, as 'this' may still be on the stack
// resulting in possible crashes when the stack unwindes.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&DesktopWindowTreeHostMus::CloseNow,
- close_widget_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&DesktopWindowTreeHostMus::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
}
void DesktopWindowTreeHostMus::CloseNow() {
@@ -495,10 +489,9 @@ void DesktopWindowTreeHostMus::CenterWindow(const gfx::Size& size) {
gfx::Rect bounds_to_center_in = GetWorkAreaBoundsInScreen();
// If there is a transient parent and it fits |size|, then center over it.
- aura::Window* content_window = desktop_native_widget_aura_->content_window();
- if (wm::GetTransientParent(content_window)) {
+ if (wm::GetTransientParent(content_window())) {
gfx::Rect transient_parent_bounds =
- wm::GetTransientParent(content_window)->GetBoundsInScreen();
+ wm::GetTransientParent(content_window())->GetBoundsInScreen();
if (transient_parent_bounds.height() >= size.height() &&
transient_parent_bounds.width() >= size.width()) {
bounds_to_center_in = transient_parent_bounds;
@@ -792,7 +785,7 @@ void DesktopWindowTreeHostMus::OnActiveFocusClientChanged(
void DesktopWindowTreeHostMus::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
- DCHECK_EQ(window, desktop_native_widget_aura_->content_window());
+ DCHECK_EQ(window, content_window());
DCHECK(!window->GetRootWindow() || this->window() == window->GetRootWindow());
if (!this->window())
return;
@@ -851,4 +844,8 @@ void DesktopWindowTreeHostMus::SetBoundsInPixels(
}
}
+aura::Window* DesktopWindowTreeHostMus::content_window() {
+ return desktop_native_widget_aura_->content_window();
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.h b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
index 2884d650d58..e1dca1c6735 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -61,8 +61,7 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
bool ShouldSendClientAreaToServer() const;
// DesktopWindowTreeHost:
- void Init(aura::Window* content_window,
- const Widget::InitParams& params) override;
+ void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
void OnActiveWindowChanged(bool active) override;
void OnWidgetInitDone() override;
@@ -143,6 +142,9 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void HideImpl() override;
void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels) override;
+ // Accessor for DesktopNativeWidgetAura::content_window().
+ aura::Window* content_window();
+
internal::NativeWidgetDelegate* native_widget_delegate_;
DesktopNativeWidgetAura* desktop_native_widget_aura_;
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index 34a105de7de..50851a87bfa 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -7,7 +7,6 @@
#include "base/debug/stack_trace.h"
#include "base/run_loop.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/transient_window_client.h"
diff --git a/chromium/ui/views/mus/drag_interactive_uitest.cc b/chromium/ui/views/mus/drag_interactive_uitest.cc
index 08bab8b2ae7..50bb37c5d49 100644
--- a/chromium/ui/views/mus/drag_interactive_uitest.cc
+++ b/chromium/ui/views/mus/drag_interactive_uitest.cc
@@ -124,11 +124,11 @@ void DragTest_Part2(int64_t display_id,
if (!result)
quit_closure.Run();
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseUpEvent(30, 30),
- base::Bind(&DragTest_Part3, display_id, quit_closure));
+ base::BindOnce(&DragTest_Part3, display_id, quit_closure));
}
void DragTest_Part1(int64_t display_id,
@@ -138,11 +138,11 @@ void DragTest_Part1(int64_t display_id,
if (!result)
quit_closure.Run();
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseMoveEvent(30, 30),
- base::Bind(&DragTest_Part2, display_id, quit_closure));
+ base::BindOnce(&DragTest_Part2, display_id, quit_closure));
}
TEST_F(DragTestInteractive, DragTest) {
@@ -175,11 +175,11 @@ TEST_F(DragTestInteractive, DragTest) {
{
base::RunLoop run_loop;
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseDownEvent(10, 10),
- base::Bind(&DragTest_Part1, display_id, run_loop.QuitClosure()));
+ base::BindOnce(&DragTest_Part1, display_id, run_loop.QuitClosure()));
run_loop.Run();
}
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 9399f8228d7..1e049056dfb 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -104,15 +104,12 @@ MusClient::MusClient(service_manager::Connector* connector,
if (testing_state == MusClientTestingState::CREATE_TESTING_STATE) {
connector->BindInterface(ui::mojom::kServiceName, &server_test_ptr_);
- connector->BindInterface(ui::mojom::kServiceName,
- &remote_event_dispatcher_ptr_);
+ connector->BindInterface(ui::mojom::kServiceName, &event_injector_);
}
- window_tree_client_ = std::make_unique<aura::WindowTreeClient>(
- connector, this, nullptr /* window_manager_delegate */,
- nullptr /* window_tree_client_request */, std::move(io_task_runner));
+ window_tree_client_ = aura::WindowTreeClient::CreateForWindowTreeFactory(
+ connector, this, true, std::move(io_task_runner));
aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client_.get());
- window_tree_client_->ConnectViaWindowTreeFactory();
pointer_watcher_event_router_ =
std::make_unique<PointerWatcherEventRouter>(window_tree_client_.get());
@@ -291,9 +288,9 @@ ui::mojom::WindowServerTest* MusClient::GetTestingInterface() const {
return server_test_ptr_.get();
}
-ui::mojom::RemoteEventDispatcher* MusClient::GetTestingEventDispater() const {
- CHECK(remote_event_dispatcher_ptr_);
- return remote_event_dispatcher_ptr_.get();
+ui::mojom::EventInjector* MusClient::GetTestingEventInjector() const {
+ CHECK(event_injector_);
+ return event_injector_.get();
}
std::unique_ptr<DesktopWindowTreeHost> MusClient::CreateDesktopWindowTreeHost(
diff --git a/chromium/ui/views/mus/mus_client.h b/chromium/ui/views/mus/mus_client.h
index 666f75eb533..0543e03247a 100644
--- a/chromium/ui/views/mus/mus_client.h
+++ b/chromium/ui/views/mus/mus_client.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/ui/public/interfaces/remote_event_dispatcher.mojom.h"
+#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "services/ui/public/interfaces/window_server_test.mojom.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/mus/window_tree_client_delegate.h"
@@ -127,9 +127,9 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// with MusClientTestingState::CREATE_TESTING_STATE.
ui::mojom::WindowServerTest* GetTestingInterface() const;
- // Returns an interface to dispatch events in the mus server. Only available
- // when created with MusClientTestingState::CREATE_TESTING_STATE.
- ui::mojom::RemoteEventDispatcher* GetTestingEventDispater() const;
+ // Returns an interface to inject events into the Window Service. Only
+ // available when created with MusClientTestingState::CREATE_TESTING_STATE.
+ ui::mojom::EventInjector* GetTestingEventInjector() const;
private:
friend class AuraInit;
@@ -182,7 +182,7 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
std::unique_ptr<PointerWatcherEventRouter> pointer_watcher_event_router_;
ui::mojom::WindowServerTestPtr server_test_ptr_;
- ui::mojom::RemoteEventDispatcherPtr remote_event_dispatcher_ptr_;
+ ui::mojom::EventInjectorPtr event_injector_;
DISALLOW_COPY_AND_ASSIGN(MusClient);
};
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
index bdccaff4aa8..7634fff74bc 100644
--- a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/mus/window_tree_client_private.h"
diff --git a/chromium/ui/views/mus/remote_view/BUILD.gn b/chromium/ui/views/mus/remote_view/BUILD.gn
new file mode 100644
index 00000000000..a5232997d72
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("remote_view_host") {
+ sources = [
+ "remote_view_host.cc",
+ "remote_view_host.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/aura",
+ "//ui/views",
+ ]
+}
+
+source_set("remote_view_provider") {
+ sources = [
+ "remote_view_provider.cc",
+ "remote_view_provider.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/aura",
+ "//ui/views",
+ "//ui/views/mus",
+ ]
+}
+
+source_set("test_support") {
+ testonly = true
+
+ sources = [
+ "remote_view_provider_test_api.cc",
+ "remote_view_provider_test_api.h",
+ ]
+
+ deps = [
+ ":remote_view_provider",
+ "//base",
+ ]
+}
+
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "remote_view_host_unittest.cc",
+ "remote_view_provider_unittest.cc",
+ ]
+
+ deps = [
+ ":remote_view_host",
+ ":remote_view_provider",
+ ":test_support",
+ "//base",
+ "//testing/gtest",
+ "//ui/aura",
+ "//ui/aura:test_support",
+ "//ui/base",
+ "//ui/views",
+ "//ui/views/mus",
+ ]
+}
diff --git a/chromium/ui/views/mus/remote_view/README.md b/chromium/ui/views/mus/remote_view/README.md
new file mode 100644
index 00000000000..391437e842e
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/README.md
@@ -0,0 +1,55 @@
+This directory contains helper classes to embed a `Window`.
+
+## `RemoteViewProvider`
+
+`RemoteViewProvider` wraps the work needed to provide a `Window` to another
+(remote) client. Typical usage is to create an instance of it with the window to
+provide to the remote client.
+
+e.g.
+```
+ ...
+
+ // Step 1: Prepares for embedding after |window_for_remote_client_| is ready.
+ void StartEmbed() {
+ remote_view_provider_ =
+ std::make_unique<views::RemoteViewProvider>(window_for_remote_client_);
+ remote_view_client->GetEmbedToken(base::BindOnce(
+ &EmbeddedClient::OnGotEmbedToken, base::Unretained(this)));
+ }
+
+ void OnGotEmbedToken(const base::UnguessableToken& token) {
+ // Step 2: Pass |token| to the embedder.
+ }
+
+ // A Window to to provide to the remote client.
+ aura::Window* window_for_remote_client_;
+
+ // Helper to prepare |window_for_remote_client_| for embedding.
+ std::unique_ptr<views::RemoteViewProvider> remote_view_provider_;
+
+ ...
+```
+
+## `RemoteViewHost`
+
+`RemoteViewHost` wraps the work on the embedder side and is a `NativeViewHost`
+that embeds the window from the `RemoteViewProvider`. `RemoveViewHost` is a
+`View` that you add to your existing `View` hierarchy.
+
+e.g.
+```
+ class EmbedderView : public views::View {
+ public:
+ ...
+ // Creates a RemoteViewHost using |token| from the embedded client.
+ void AddEmbeddedView(const base::UnguessableToken& token) {
+ // Ownership will be passed to the view hierarchy in AddChildView.
+ views::RemoteViewHost* remote_view_host = new RemoteViewHost();
+ remote_view_host->EmbedUsingToken(token, base::DoNothing());
+ AddChildView(remote_view_host);
+ }
+ ...
+ };
+```
+
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.cc b/chromium/ui/views/mus/remote_view/remote_view_host.cc
new file mode 100644
index 00000000000..c5f9e577de0
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.cc
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/mus/remote_view/remote_view_host.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/mus/window_port_mus.h"
+
+namespace views {
+
+RemoteViewHost::RemoteViewHost() = default;
+RemoteViewHost::~RemoteViewHost() = default;
+
+void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
+ int embed_flags,
+ EmbedCallback callback) {
+ // Only works with mus.
+ DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstanceDontCreate()->mode());
+
+ embed_token_ = embed_token;
+ embed_flags_ = embed_flags;
+ embed_callback_ = std::move(callback);
+
+ if (GetWidget())
+ CreateEmbeddingRoot();
+}
+
+void RemoteViewHost::CreateEmbeddingRoot() {
+ // Should not be attached to anything.
+ DCHECK(!native_view());
+
+ // There is a pending embed request.
+ DCHECK(!embed_token_.is_empty());
+
+ embedding_root_ = std::make_unique<aura::Window>(nullptr);
+ embedding_root_->set_owned_by_parent(false);
+
+ embedding_root_->SetName("RemoteViewHostWindow");
+ embedding_root_->SetProperty(aura::client::kEmbedType,
+ aura::client::WindowEmbedType::EMBED_IN_OWNER);
+ embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL);
+ embedding_root_->Init(ui::LAYER_NOT_DRAWN);
+
+ // Must happen before EmbedUsingToken call for window server to figure out
+ // the relevant display.
+ Attach(embedding_root_.get());
+
+ aura::WindowPortMus::Get(embedding_root_.get())
+ ->EmbedUsingToken(embed_token_, embed_flags_,
+ base::BindOnce(&RemoteViewHost::OnEmbedResult,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RemoteViewHost::OnEmbedResult(bool success) {
+ LOG_IF(ERROR, !success) << "Failed to embed, token=" << embed_token_;
+
+ if (!success && embedding_root_)
+ embedding_root_.reset();
+
+ if (embed_callback_)
+ std::move(embed_callback_).Run(success);
+}
+
+void RemoteViewHost::AddedToWidget() {
+ if (!native_view() && !embed_token_.is_empty())
+ CreateEmbeddingRoot();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.h b/chromium/ui/views/mus/remote_view/remote_view_host.h
new file mode 100644
index 00000000000..44b1552f325
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/native/native_view_host.h"
+
+namespace views {
+
+// A view at the embedder side to embed an aura::Window from another window
+// tree. Note this only works with mus.
+class RemoteViewHost : public views::NativeViewHost {
+ public:
+ RemoteViewHost();
+ ~RemoteViewHost() override;
+
+ // Embeds the remote contents after this view is added to a widget.
+ // |embed_token| is the token obtained from the WindowTree embed API
+ // (ScheduleEmbed/ForExistingClient). |embed_flags| are the embedding flags
+ // (see window_tree_constants.mojom). |callback| is an optional callback
+ // invoked with the embed result.
+ // Note that |callback| should not be used to add the view to a widget because
+ // the actual embedding only happens after the view is added.
+ using EmbedCallback = base::OnceCallback<void(bool success)>;
+ void EmbedUsingToken(const base::UnguessableToken& embed_token,
+ int embed_flags,
+ EmbedCallback callback);
+
+ private:
+ // Creates the embedding aura::Window and attach to it.
+ void CreateEmbeddingRoot();
+
+ // Invoked after the embed operation.
+ void OnEmbedResult(bool success);
+
+ // views::NativeViewHost:
+ void AddedToWidget() override;
+
+ base::UnguessableToken embed_token_;
+ int embed_flags_ = 0;
+ EmbedCallback embed_callback_;
+
+ std::unique_ptr<aura::Window> embedding_root_;
+ base::WeakPtrFactory<RemoteViewHost> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewHost);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
new file mode 100644
index 00000000000..611c00151cd
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
@@ -0,0 +1,151 @@
+// 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/mus/remote_view/remote_view_host.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+
+namespace {
+
+// Embeds using |token| and waits for it. Returns true if embed succeeds.
+bool Embed(RemoteViewHost* host, const base::UnguessableToken& token) {
+ base::RunLoop run_loop;
+ bool embed_result = false;
+ host->EmbedUsingToken(
+ token, 0u /* no flags */,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* result, bool success) {
+ *result = success;
+ run_loop->Quit();
+ },
+ &run_loop, &embed_result));
+ run_loop.Run();
+ return embed_result;
+}
+
+} // namespace
+
+class RemoteViewHostTest : public aura::test::AuraTestBase {
+ public:
+ RemoteViewHostTest() = default;
+ ~RemoteViewHostTest() override = default;
+
+ // aura::test::AuraTestBase
+ void SetUp() override {
+ EnableMusWithTestWindowTree();
+ AuraTestBase::SetUp();
+ }
+
+ // Creates a widget to host |contents|.
+ std::unique_ptr<views::Widget> CreateTestWidget(views::View* contents) {
+ std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ params.context = root_window();
+ widget->Init(params);
+ widget->SetContentsView(contents);
+
+ return widget;
+ }
+
+ // Helper callback invoked during embed to simulate adding to widget during
+ // embed operation.
+ void CreateTestWidgetWhileEmbeddingHelper(
+ base::RunLoop* run_loop,
+ views::View* contents,
+ std::unique_ptr<views::Widget>* widget,
+ bool success) {
+ ASSERT_TRUE(success);
+ *widget = CreateTestWidget(contents);
+ run_loop->Quit();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewHostTest);
+};
+
+// Tests that the embed operation fails with an unknown token and RemoteViewHost
+// will not be attached.
+TEST_F(RemoteViewHostTest, BadEmbed) {
+ const base::UnguessableToken unknown_token = base::UnguessableToken::Create();
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ EXPECT_FALSE(host->native_view());
+
+ // Embed fails with unknown token.
+ EXPECT_FALSE(Embed(host, unknown_token));
+
+ // |host| is not attached after adding to a widget.
+ EXPECT_FALSE(host->native_view());
+}
+
+// Tests when RemoveViewHost is added to a widget before embedding.
+TEST_F(RemoteViewHostTest, AddToWidgetBeforeEmbed) {
+ const base::UnguessableToken token = base::UnguessableToken::Create();
+ window_tree()->AddScheduledEmbedToken(token);
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+
+ // |host| is not attached because embed operation is not performed.
+ EXPECT_FALSE(host->native_view());
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ EXPECT_FALSE(host->native_view());
+
+ // Embed succeeds.
+ EXPECT_TRUE(Embed(host, token));
+
+ // |host| is now attached to the embedding window.
+ EXPECT_TRUE(host->native_view());
+}
+
+// Tests when RemoveViewHost is added to a widget after embedding.
+TEST_F(RemoteViewHostTest, AddToWidgetAfterEmbed) {
+ const base::UnguessableToken token = base::UnguessableToken::Create();
+ window_tree()->AddScheduledEmbedToken(token);
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+
+ // Request embedding but it will be deferred until added to a widget.
+ base::RunLoop run_loop;
+ bool embed_result = false;
+ host->EmbedUsingToken(
+ token, 0u /* no flags */,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* result, bool success) {
+ *result = success;
+ run_loop->Quit();
+ },
+ &run_loop, &embed_result));
+
+ // |host| is not attached before adding to a widget.
+ EXPECT_FALSE(host->native_view());
+
+ // Add to a widget and wait for embed to finish.
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ run_loop.Run();
+
+ // |host| is attached after added to a widget.
+ EXPECT_TRUE(host->native_view());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.cc b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
new file mode 100644
index 00000000000..12286cd26af
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
@@ -0,0 +1,154 @@
+// 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/mus/remote_view/remote_view_provider.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/mus/embed_root.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/mus/mus_client.h"
+
+namespace views {
+
+// static
+aura::WindowTreeClient* RemoteViewProvider::window_tree_client_for_test =
+ nullptr;
+
+// Observes a window and invokes a callback when the window is destroyed.
+class RemoteViewProvider::EmbeddedWindowObserver : public aura::WindowObserver {
+ public:
+ EmbeddedWindowObserver(aura::Window* window, base::OnceClosure on_destroyed)
+ : window_observer_(this), on_destroyed_(std::move(on_destroyed)) {
+ window_observer_.Add(window);
+ }
+ ~EmbeddedWindowObserver() override = default;
+
+ // aura::WindowObserver:
+ void OnWindowDestroyed(aura::Window* window) override {
+ DCHECK(!on_destroyed_.is_null());
+
+ window_observer_.RemoveAll();
+ base::ResetAndReturn(&on_destroyed_).Run();
+ }
+
+ private:
+ ScopedObserver<aura::Window, EmbeddedWindowObserver> window_observer_;
+ base::OnceClosure on_destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWindowObserver);
+};
+
+// Observes a window and invokes a callback when the window size changes.
+class RemoteViewProvider::EmbeddingWindowObserver
+ : public aura::WindowObserver {
+ public:
+ using SizeChangedCallback = base::RepeatingCallback<void(const gfx::Size&)>;
+ EmbeddingWindowObserver(aura::Window* window,
+ const SizeChangedCallback& callback)
+ : window_observer_(this), on_size_changed_(callback) {
+ window_observer_.Add(window);
+ }
+ ~EmbeddingWindowObserver() override = default;
+
+ // aura::WindowObserver:
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) override {
+ on_size_changed_.Run(new_bounds.size());
+ }
+ void OnWindowDestroyed(aura::Window* window) override {
+ window_observer_.RemoveAll();
+ }
+
+ private:
+ ScopedObserver<aura::Window, EmbeddingWindowObserver> window_observer_;
+ SizeChangedCallback on_size_changed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddingWindowObserver);
+};
+
+RemoteViewProvider::RemoteViewProvider(aura::Window* embedded)
+ : embedded_(embedded) {
+ DCHECK(embedded_);
+ embedded_window_observer_ = std::make_unique<EmbeddedWindowObserver>(
+ embedded_, base::BindOnce(&RemoteViewProvider::OnEmbeddedWindowDestroyed,
+ base::Unretained(this)));
+}
+
+RemoteViewProvider::~RemoteViewProvider() = default;
+
+void RemoteViewProvider::GetEmbedToken(GetEmbedTokenCallback callback) {
+ DCHECK(embedded_);
+
+ if (embed_root_) {
+ std::move(callback).Run(embed_root_->token());
+ return;
+ }
+
+ DCHECK(get_embed_token_callback_.is_null());
+ get_embed_token_callback_ = std::move(callback);
+
+ aura::WindowTreeClient* window_tree_client = window_tree_client_for_test;
+ if (!window_tree_client) {
+ DCHECK(views::MusClient::Exists());
+ window_tree_client = views::MusClient::Get()->window_tree_client();
+ }
+
+ embed_root_ = window_tree_client->CreateEmbedRoot(this);
+}
+
+void RemoteViewProvider::SetCallbacks(const OnEmbedCallback& on_embed,
+ const OnUnembedCallback& on_unembed) {
+ on_embed_callback_ = on_embed;
+ on_unembed_callback_ = on_unembed;
+}
+
+void RemoteViewProvider::OnEmbeddedWindowDestroyed() {
+ embedded_ = nullptr;
+}
+
+void RemoteViewProvider::OnEmbeddingWindowResized(const gfx::Size& size) {
+ // |embedded_| is owned by external code. Bail if it is destroyed while being
+ // embedded.
+ if (!embedded_)
+ return;
+ embedded_->SetBounds(gfx::Rect(size));
+}
+
+void RemoteViewProvider::OnEmbedTokenAvailable(
+ const base::UnguessableToken& token) {
+ if (get_embed_token_callback_)
+ std::move(get_embed_token_callback_).Run(token);
+}
+
+void RemoteViewProvider::OnEmbed(aura::Window* window) {
+ DCHECK(embedded_);
+
+ embedding_window_observer_ = std::make_unique<EmbeddingWindowObserver>(
+ window, base::BindRepeating(&RemoteViewProvider::OnEmbeddingWindowResized,
+ base::Unretained(this)));
+ OnEmbeddingWindowResized(window->bounds().size());
+ window->AddChild(embedded_);
+
+ if (on_embed_callback_)
+ on_embed_callback_.Run(window);
+}
+
+void RemoteViewProvider::OnUnembed() {
+ embedding_window_observer_.reset();
+ embed_root_.reset();
+
+ if (on_unembed_callback_)
+ on_unembed_callback_.Run();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.h b/chromium/ui/views/mus/remote_view/remote_view_provider.h
new file mode 100644
index 00000000000..9717d5f8a76
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.h
@@ -0,0 +1,98 @@
+// 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_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/mus/embed_root_delegate.h"
+
+namespace aura {
+class EmbedRoot;
+class Window;
+class WindowTreeClient;
+} // namespace aura
+
+namespace gfx {
+class Size;
+}
+
+namespace views {
+
+namespace test {
+class RemoteViewProviderTestApi;
+}
+
+// Creates an EmbedRoot for an embedded aura::Window on the client side and
+// updates the embedded window size when the embedder changes size. For example,
+// allows app list in ash to embed web-based "answer cards" that are rendered
+// by the browser. Note this works only with mus.
+class RemoteViewProvider : public aura::EmbedRootDelegate {
+ public:
+ explicit RemoteViewProvider(aura::Window* embedded);
+ ~RemoteViewProvider() override;
+
+ static void SetWindowTreeClientForTest(aura::WindowTreeClient* tree_client);
+
+ // Gets the embed token. An embed token is obtained from one of WindowTree's
+ // schedule embed calls (ScheduleEmbed or ScheduleEmbedForExistingClient). An
+ // embedder calls EmbedUsingToken using the token to embed desired contents.
+ // The embed token here is from an aura::EmbedRoot that uses
+ // ScheduleEmbedForExistingClient for embedding part of an existing
+ // WindowTreeClient. |callback| is invoked when the token is available.
+ using GetEmbedTokenCallback =
+ base::OnceCallback<void(const base::UnguessableToken& token)>;
+ void GetEmbedToken(GetEmbedTokenCallback callback);
+
+ // Optional callbacks to be invoked when embed or unembed happens.
+ using OnEmbedCallback = base::RepeatingCallback<void(aura::Window* embedder)>;
+ using OnUnembedCallback = base::RepeatingClosure;
+ void SetCallbacks(const OnEmbedCallback& on_embed,
+ const OnUnembedCallback& on_unembed);
+
+ private:
+ friend class test::RemoteViewProviderTestApi;
+
+ class EmbeddedWindowObserver;
+ class EmbeddingWindowObserver;
+
+ // Invoked when |embedded_| is destroyed.
+ void OnEmbeddedWindowDestroyed();
+
+ // Invoked when embedder changes size.
+ void OnEmbeddingWindowResized(const gfx::Size& size);
+
+ // aura::EmbedRootDelegate:
+ void OnEmbedTokenAvailable(const base::UnguessableToken& token) override;
+ void OnEmbed(aura::Window* window) override;
+ void OnUnembed() override;
+
+ // An aura::Window to be embedded. Not owned.
+ aura::Window* embedded_;
+
+ std::unique_ptr<aura::EmbedRoot> embed_root_;
+ GetEmbedTokenCallback get_embed_token_callback_;
+ OnEmbedCallback on_embed_callback_;
+ OnUnembedCallback on_unembed_callback_;
+
+ // An aura::WindowTreeClient for test. Use RemoteViewProviderTestApi to set
+ // it.
+ static aura::WindowTreeClient* window_tree_client_for_test;
+
+ // Observes the |embedded_| and clears it when it is gone.
+ std::unique_ptr<EmbeddedWindowObserver> embedded_window_observer_;
+
+ // Observes the embeddding window provided by embedder.
+ std::unique_ptr<EmbeddingWindowObserver> embedding_window_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProvider);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc
new file mode 100644
index 00000000000..c3668ba2114
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
+
+#include "ui/views/mus/remote_view/remote_view_provider.h"
+
+namespace views {
+namespace test {
+
+void RemoteViewProviderTestApi::SetWindowTreeClient(
+ aura::WindowTreeClient* window_tree_client) {
+ RemoteViewProvider::window_tree_client_for_test = window_tree_client;
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h
new file mode 100644
index 00000000000..49212fa6762
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
+
+#include "base/macros.h"
+
+namespace aura {
+class WindowTreeClient;
+}
+
+namespace views {
+namespace test {
+
+class RemoteViewProviderTestApi {
+ public:
+ // Sets an aura::WindowTreeClient to use with RemoteViewProvider.
+ static void SetWindowTreeClient(aura::WindowTreeClient* window_tree_client);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProviderTestApi);
+};
+
+} // namespace test
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
new file mode 100644
index 00000000000..f87a3202ebc
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/mus/remote_view/remote_view_provider.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/mus/window_mus.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
+
+namespace views {
+
+class RemoteViewProviderTest : public aura::test::AuraTestBase {
+ public:
+ RemoteViewProviderTest() = default;
+ ~RemoteViewProviderTest() override = default;
+
+ // aura::test::AuraTestBase
+ void SetUp() override {
+ EnableMusWithTestWindowTree();
+ AuraTestBase::SetUp();
+
+ test::RemoteViewProviderTestApi::SetWindowTreeClient(
+ window_tree_client_impl());
+
+ embedded_ = std::make_unique<aura::Window>(nullptr);
+ embedded_->set_owned_by_parent(false);
+ embedded_->Init(ui::LAYER_NOT_DRAWN);
+ embedded_->SetBounds(gfx::Rect(100, 50));
+
+ provider_ = std::make_unique<RemoteViewProvider>(embedded_.get());
+ }
+
+ void TearDown() override {
+ // EmbedRoot in |provider_| must be released before WindowTreeClient.
+ provider_.reset();
+
+ AuraTestBase::TearDown();
+ }
+
+ // Gets the embed token and waits for it.
+ base::UnguessableToken GetEmbedToken() {
+ base::RunLoop run_loop;
+ base::UnguessableToken token;
+ provider_->GetEmbedToken(base::BindOnce(
+ [](base::RunLoop* run_loop, base::UnguessableToken* out_token,
+ const base::UnguessableToken& token) {
+ *out_token = token;
+ run_loop->Quit();
+ },
+ &run_loop, &token));
+ run_loop.Run();
+ return token;
+ }
+
+ // Simulates EmbedUsingToken call on embedder side and waits for
+ // WindowTreeClient to create a local embedder window.
+ aura::Window* SimulateEmbedUsingTokenAndGetEmbedder(
+ const base::UnguessableToken& token) {
+ base::RunLoop run_loop;
+ aura::Window* embedder = nullptr;
+ provider_->SetCallbacks(
+ base::BindRepeating(
+ [](base::RunLoop* run_loop, aura::Window** out_embedder,
+ aura::Window* embedder) {
+ *out_embedder = embedder;
+ run_loop->Quit();
+ },
+ &run_loop, &embedder),
+ base::DoNothing() /* OnUnembedCallback */);
+ window_tree()->AddEmbedRootForToken(token);
+ run_loop.Run();
+ return embedder;
+ }
+
+ // Helper to simulate embed.
+ aura::Window* SimulateEmbed() {
+ base::UnguessableToken token = GetEmbedToken();
+ if (token.is_empty()) {
+ ADD_FAILURE() << "Failed to get embed token.";
+ return nullptr;
+ }
+
+ return SimulateEmbedUsingTokenAndGetEmbedder(token);
+ }
+
+ // Simulates the embedder window close.
+ void SimulateEmbedderClose(aura::Window* embedder) {
+ base::RunLoop run_loop;
+ provider_->SetCallbacks(
+ base::DoNothing() /* OnEmbedCallback */,
+ base::BindRepeating([](base::RunLoop* run_loop) { run_loop->Quit(); },
+ &run_loop));
+
+ const ui::Id embedder_window_id =
+ aura::WindowMus::Get(embedder)->server_id();
+ window_tree()->RemoveEmbedderWindow(embedder_window_id);
+ run_loop.Run();
+ }
+
+ protected:
+ std::unique_ptr<aura::Window> embedded_;
+ std::unique_ptr<RemoteViewProvider> provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProviderTest);
+};
+
+// Tests the basics on the embedded client.
+TEST_F(RemoteViewProviderTest, Embed) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ // |embedded_| has the same non-empty size with |embedder| after embed.
+ EXPECT_EQ(embedded_->bounds().size(), embedder->bounds().size());
+ EXPECT_FALSE(embedded_->bounds().IsEmpty());
+ EXPECT_FALSE(embedder->bounds().IsEmpty());
+
+ // |embedded_| resizes with |embedder|.
+ const gfx::Rect new_bounds(embedder->bounds().width() + 100,
+ embedder->bounds().height() + 50);
+ embedder->SetBounds(new_bounds);
+ EXPECT_EQ(embedded_->bounds().size(), embedder->bounds().size());
+ EXPECT_FALSE(embedded_->bounds().IsEmpty());
+ EXPECT_FALSE(embedder->bounds().IsEmpty());
+}
+
+// Tests when |embedded_| is released first.
+TEST_F(RemoteViewProviderTest, EmbeddedReleasedFirst) {
+ SimulateEmbed();
+ embedded_.reset();
+}
+
+// Tests when |provider_| is released first.
+TEST_F(RemoteViewProviderTest, ClientReleasedFirst) {
+ SimulateEmbed();
+ provider_.reset();
+}
+
+// Tests when embedder goes away first.
+TEST_F(RemoteViewProviderTest, EmbedderReleasedFirst) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ SimulateEmbedderClose(embedder);
+}
+
+// Tests that the client can embed again.
+TEST_F(RemoteViewProviderTest, EmbedAgain) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ SimulateEmbedderClose(embedder);
+
+ aura::Window* new_embedder = SimulateEmbed();
+ ASSERT_TRUE(new_embedder);
+ EXPECT_NE(new_embedder, embedder);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 0008b8eeaf4..3b2cfcd1c39 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -10,7 +10,6 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
@@ -86,8 +85,8 @@ class ServiceManagerConnection {
base::Thread::Options options;
thread_.StartWithOptions(options);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::SetUpConnections,
- base::Unretained(this), &wait));
+ FROM_HERE, base::BindOnce(&ServiceManagerConnection::SetUpConnections,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -95,8 +94,9 @@ class ServiceManagerConnection {
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::TearDownConnections,
- base::Unretained(this), &wait));
+ FROM_HERE,
+ base::BindOnce(&ServiceManagerConnection::TearDownConnections,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -111,8 +111,8 @@ class ServiceManagerConnection {
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::CloneConnector,
- base::Unretained(this), &wait));
+ FROM_HERE, base::BindOnce(&ServiceManagerConnection::CloneConnector,
+ base::Unretained(this), &wait));
wait.Wait();
DCHECK(service_manager_connector_);
return service_manager_connector_.get();
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index 85ee0946242..d93eacd40f1 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -5,7 +5,6 @@
#include "ui/views/painter.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
diff --git a/chromium/ui/views/selection_controller.cc b/chromium/ui/views/selection_controller.cc
index aa400d8bf22..b4a3a403932 100644
--- a/chromium/ui/views/selection_controller.cc
+++ b/chromium/ui/views/selection_controller.cc
@@ -164,7 +164,8 @@ void SelectionController::TrackMouseClicks(const ui::MouseEvent& event) {
base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
if (!last_click_time_.is_null() &&
time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
- !View::ExceededDragThreshold(event.location() - last_click_location_)) {
+ !View::ExceededDragThreshold(event.root_location() -
+ last_click_location_)) {
// Upon clicking after a triple click, the count should go back to
// double click and alternate between double and triple. This assignment
// maps 0 to 1, 1 to 2, 2 to 1.
@@ -173,7 +174,7 @@ void SelectionController::TrackMouseClicks(const ui::MouseEvent& event) {
aggregated_clicks_ = 0;
}
last_click_time_ = event.time_stamp();
- last_click_location_ = event.location();
+ last_click_location_ = event.root_location();
}
}
diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc
index b12430178e9..99793bc88bd 100644
--- a/chromium/ui/views/style/platform_style.cc
+++ b/chromium/ui/views/style/platform_style.cc
@@ -4,11 +4,12 @@
#include "ui/views/style/platform_style.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/range/range.h"
#include "ui/gfx/shadow_value.h"
+#include "ui/gfx/utf16_indexing.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
@@ -55,6 +56,7 @@ const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = false;
const bool PlatformStyle::kUseRipples = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = false;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = true;
+const bool PlatformStyle::kShouldElideBookmarksInBookmarksBar = false;
// static
std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
@@ -68,6 +70,15 @@ std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
// static
void PlatformStyle::OnTextfieldEditFailed() {}
+// static
+gfx::Range PlatformStyle::RangeToDeleteBackwards(const base::string16& text,
+ size_t cursor_position) {
+ // Delete one code point, which may be two UTF-16 words.
+ size_t previous_grapheme_index =
+ gfx::UTF16OffsetToIndex(text, cursor_position, -1);
+ return gfx::Range(cursor_position, previous_grapheme_index);
+}
+
#endif // OS_MACOSX
#if !defined(DESKTOP_LINUX)
diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h
index d5b7e3bf951..25710b7968e 100644
--- a/chromium/ui/views/style/platform_style.h
+++ b/chromium/ui/views/style/platform_style.h
@@ -11,6 +11,10 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/views_export.h"
+namespace gfx {
+class Range;
+} // namespace gfx
+
namespace views {
class Border;
@@ -66,6 +70,10 @@ class VIEWS_EXPORT PlatformStyle {
// dragging but available to do so.
static const bool kTextfieldUsesDragCursorWhenDraggable;
+ // Whether bookmarks in the bookmarks bar are elided [and show elipses at the
+ // tail] or fade out.
+ static const bool kShouldElideBookmarksInBookmarksBar;
+
// Creates the default scrollbar for the given orientation.
static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal);
@@ -83,6 +91,14 @@ class VIEWS_EXPORT PlatformStyle {
// the failed edit if platform-appropriate.
static void OnTextfieldEditFailed();
+ // When deleting backwards in |string| with the cursor at index
+ // |cursor_position|, return the range of UTF-16 words to be deleted.
+ // This is to support deleting entire graphemes instead of individual
+ // characters when necessary on Mac, and code points made from surrogate
+ // pairs on other platforms.
+ static gfx::Range RangeToDeleteBackwards(const base::string16& text,
+ size_t cursor_position);
+
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 5d14515be15..36cdfff642d 100644
--- a/chromium/ui/views/style/platform_style_mac.mm
+++ b/chromium/ui/views/style/platform_style_mac.mm
@@ -4,7 +4,7 @@
#include "ui/views/style/platform_style.h"
-#include "base/memory/ptr_util.h"
+#include "base/strings/sys_string_conversions.h"
#include "ui/base/ui_features.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/controls/button/label_button.h"
@@ -12,6 +12,24 @@
#import <Cocoa/Cocoa.h>
+extern "C" {
+// From CFString private headers.
+typedef CF_ENUM(CFIndex, CFStringCharacterClusterType) {
+ kCFStringGraphemeCluster = 1, /* Unicode Grapheme Cluster */
+ kCFStringComposedCharacterCluster =
+ 2, /* Compose all non-base (including spacing marks) */
+ kCFStringCursorMovementCluster =
+ 3, /* Cluster suitable for cursor movements */
+ kCFStringBackwardDeletionCluster =
+ 4 /* Cluster suitable for backward deletion */
+};
+
+CFRange CFStringGetRangeOfCharacterClusterAtIndex(
+ CFStringRef string,
+ CFIndex index,
+ CFStringCharacterClusterType type);
+}
+
namespace views {
const int PlatformStyle::kMinLabelButtonWidth = 32;
@@ -22,6 +40,7 @@ const bool PlatformStyle::kSelectAllOnRightClickWhenUnfocused = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = true;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = false;
const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true;
+const bool PlatformStyle::kShouldElideBookmarksInBookmarksBar = true;
const bool PlatformStyle::kUseRipples = false;
const Button::NotifyAction PlatformStyle::kMenuNotifyActivationAction =
@@ -44,4 +63,23 @@ void PlatformStyle::OnTextfieldEditFailed() {
NSBeep();
}
+// static
+gfx::Range PlatformStyle::RangeToDeleteBackwards(const base::string16& text,
+ size_t cursor_position) {
+ if (cursor_position == 0)
+ return gfx::Range();
+
+ base::ScopedCFTypeRef<CFStringRef> cf_string(
+ CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, text.data(),
+ text.size(), kCFAllocatorNull));
+ CFRange range_to_delete = CFStringGetRangeOfCharacterClusterAtIndex(
+ cf_string, cursor_position - 1, kCFStringBackwardDeletionCluster);
+
+ if (range_to_delete.location == NSNotFound)
+ return gfx::Range();
+
+ // The range needs to be reversed to undo correctly.
+ return gfx::Range(range_to_delete.location + range_to_delete.length,
+ range_to_delete.location);
+}
} // namespace views
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 4fa1a8a98e8..6e5d1816bff 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -210,16 +210,9 @@ typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView;
// cursor and expanding the hit-test area just below the visible drag handle.
class TouchHandleWindowTargeter : public aura::WindowTargeter {
public:
- TouchHandleWindowTargeter() = default;
- ~TouchHandleWindowTargeter() override = default;
-
void SetHitTestOffset(int offset) {
- const gfx::Insets insets(offset, 0, -offset, 0);
- SetInsets(insets, insets);
+ SetInsets(gfx::Insets(offset, 0, -offset, 0));
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter);
};
// A View that displays the text selection handle.
diff --git a/chromium/ui/views/vector_icons/checkbox_active.icon b/chromium/ui/views/vector_icons/checkbox_active.icon
index 199c3fd90d0..d9ffe0349cf 100644
--- a/chromium/ui/views/vector_icons/checkbox_active.icon
+++ b/chromium/ui/views/vector_icons/checkbox_active.icon
@@ -23,6 +23,4 @@ LINE_TO, 4.5f, 7,
LINE_TO, 6.5f, 9,
LINE_TO, 11.5f, 4.5f,
LINE_TO, 12.5f, 5.5f,
-CLOSE,
-
-END
+CLOSE
diff --git a/chromium/ui/views/vector_icons/checkbox_normal.icon b/chromium/ui/views/vector_icons/checkbox_normal.icon
index 0b1efe54c03..8ea38e0107d 100644
--- a/chromium/ui/views/vector_icons/checkbox_normal.icon
+++ b/chromium/ui/views/vector_icons/checkbox_normal.icon
@@ -22,6 +22,4 @@ CUBIC_TO, 13.551f, 14, 14, 13.551f, 14, 12.996f,
V_LINE_TO, 3.004f,
CUBIC_TO, 14, 2.449f, 13.551f, 2, 12.996f, 2,
LINE_TO, 12.996f, 2,
-CLOSE,
-
-END
+CLOSE
diff --git a/chromium/ui/views/vector_icons/close.icon b/chromium/ui/views/vector_icons/close.icon
new file mode 100644
index 00000000000..0786371e70d
--- /dev/null
+++ b/chromium/ui/views/vector_icons/close.icon
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 12.07f, 6.8f,
+LINE_TO, 10, 8.87f,
+LINE_TO, 7.93f, 6.8f,
+LINE_TO, 6.8f, 7.93f,
+LINE_TO, 8.87f, 10,
+LINE_TO, 6.8f, 12.07f,
+LINE_TO, 7.93f, 13.2f,
+LINE_TO, 10, 11.13f,
+R_LINE_TO, 2.07f, 2.07f,
+R_LINE_TO, 1.13f, -1.13f,
+LINE_TO, 11.13f, 10,
+LINE_TO, 13.2f, 7.93f,
+LINE_TO, 12.07f, 6.8f,
+CLOSE,
+MOVE_TO, 10, 2,
+R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
+R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
+R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8,
+R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
+CLOSE,
+R_MOVE_TO, 0, 14,
+R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
+R_CUBIC_TO, 0, -3.31f, 2.69f, -6, 6, -6,
+R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
+R_CUBIC_TO, 0, 3.31f, -2.69f, 6, -6, 6,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/ic_close.icon b/chromium/ui/views/vector_icons/ic_close.icon
new file mode 100644
index 00000000000..686da72bcda
--- /dev/null
+++ b/chromium/ui/views/vector_icons/ic_close.icon
@@ -0,0 +1,33 @@
+// 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.
+
+CANVAS_DIMENSIONS, 48,
+MOVE_TO, 38, 12.82f,
+LINE_TO, 35.18f, 10,
+LINE_TO, 24, 21.18f,
+LINE_TO, 12.82f, 10,
+LINE_TO, 10, 12.82f,
+LINE_TO, 21.18f, 24,
+LINE_TO, 10, 35.18f,
+LINE_TO, 12.82f, 38,
+LINE_TO, 24, 26.82f,
+LINE_TO, 35.18f, 38,
+LINE_TO, 38, 35.18f,
+LINE_TO, 26.82f, 24,
+CLOSE
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 19, 6.41f,
+LINE_TO, 17.59f, 5,
+LINE_TO, 12, 10.59f,
+LINE_TO, 6.41f, 5,
+LINE_TO, 5, 6.41f,
+LINE_TO, 10.59f, 12,
+LINE_TO, 5, 17.59f,
+LINE_TO, 6.41f, 19,
+LINE_TO, 12, 13.41f,
+LINE_TO, 17.59f, 19,
+LINE_TO, 19, 17.59f,
+LINE_TO, 13.41f, 12,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/info.icon b/chromium/ui/views/vector_icons/info.icon
new file mode 100644
index 00000000000..2044827534a
--- /dev/null
+++ b/chromium/ui/views/vector_icons/info.icon
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 9, 14,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -4,
+H_LINE_TO, 9,
+R_V_LINE_TO, 4,
+CLOSE,
+R_MOVE_TO, 1, -12,
+R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
+R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
+R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8,
+R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
+CLOSE,
+R_MOVE_TO, 0, 14,
+R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
+R_CUBIC_TO, 0, -3.31f, 2.69f, -6, 6, -6,
+R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
+R_CUBIC_TO, 0, 3.31f, -2.69f, 6, -6, 6,
+CLOSE,
+MOVE_TO, 9, 8,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6,
+H_LINE_TO, 9,
+R_V_LINE_TO, 2,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/launch.icon b/chromium/ui/views/vector_icons/launch.icon
new file mode 100644
index 00000000000..8c97192cc12
--- /dev/null
+++ b/chromium/ui/views/vector_icons/launch.icon
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 16, 16,
+H_LINE_TO, 4,
+V_LINE_TO, 4,
+R_H_LINE_TO, 6,
+V_LINE_TO, 2,
+H_LINE_TO, 4,
+CUBIC_TO, 3, 2, 2, 3, 2, 4,
+R_V_LINE_TO, 12,
+R_CUBIC_TO, 0, 1, 1, 2, 2, 2,
+R_H_LINE_TO, 12,
+R_CUBIC_TO, 1, 0, 2, -1, 2, -2,
+R_V_LINE_TO, -6,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, 6,
+CLOSE,
+MOVE_TO, 12, 2,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 2.5f,
+LINE_TO, 6, 12.5f,
+LINE_TO, 7.5f, 14,
+LINE_TO, 16, 5.5f,
+V_LINE_TO, 8,
+R_H_LINE_TO, 2,
+V_LINE_TO, 2,
+R_H_LINE_TO, -6,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/menu_check.1x.icon b/chromium/ui/views/vector_icons/menu_check.1x.icon
deleted file mode 100644
index 739f6682e31..00000000000
--- a/chromium/ui/views/vector_icons/menu_check.1x.icon
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 2, 9.22f,
-R_LINE_TO, 1.36f, -1.38f,
-R_LINE_TO, 2.4f, 2.48f,
-R_LINE_TO, 7.2f, -7.4f,
-R_LINE_TO, 1.35f, 1.39f,
-R_LINE_TO, -8.55f, 8.78f,
-LINE_TO, 2, 9.22f,
-CLOSE,
-END
diff --git a/chromium/ui/views/vector_icons/menu_check.icon b/chromium/ui/views/vector_icons/menu_check.icon
index c06a2ccf0ee..3e24215cc5a 100644
--- a/chromium/ui/views/vector_icons/menu_check.icon
+++ b/chromium/ui/views/vector_icons/menu_check.icon
@@ -10,5 +10,14 @@ LINE_TO, 25.48f, 7,
LINE_TO, 28, 9.59f,
LINE_TO, 12.02f, 26,
LINE_TO, 5, 18.78f,
-CLOSE,
-END
+CLOSE
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 2, 9.22f,
+R_LINE_TO, 1.36f, -1.38f,
+R_LINE_TO, 2.4f, 2.48f,
+R_LINE_TO, 7.2f, -7.4f,
+R_LINE_TO, 1.35f, 1.39f,
+R_LINE_TO, -8.55f, 8.78f,
+LINE_TO, 2, 9.22f,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/menu_radio_empty.icon b/chromium/ui/views/vector_icons/menu_radio_empty.icon
index 62ef2daec82..047257b4759 100644
--- a/chromium/ui/views/vector_icons/menu_radio_empty.icon
+++ b/chromium/ui/views/vector_icons/menu_radio_empty.icon
@@ -4,5 +4,4 @@
CANVAS_DIMENSIONS, 32,
CIRCLE, 16, 16, 14,
-CIRCLE, 16, 16, 11,
-END
+CIRCLE, 16, 16, 11
diff --git a/chromium/ui/views/vector_icons/menu_radio_selected.icon b/chromium/ui/views/vector_icons/menu_radio_selected.icon
index 0533b99ba7e..5f94564ccec 100644
--- a/chromium/ui/views/vector_icons/menu_radio_selected.icon
+++ b/chromium/ui/views/vector_icons/menu_radio_selected.icon
@@ -5,5 +5,4 @@
CANVAS_DIMENSIONS, 32,
CIRCLE, 16, 16, 14,
CIRCLE, 16, 16, 11,
-CIRCLE, 16, 16, 7,
-END
+CIRCLE, 16, 16, 7
diff --git a/chromium/ui/views/vector_icons/new_incognito_window.icon b/chromium/ui/views/vector_icons/new_incognito_window.icon
new file mode 100644
index 00000000000..68d83e4898f
--- /dev/null
+++ b/chromium/ui/views/vector_icons/new_incognito_window.icon
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 8.13f, 2.04f,
+LINE_TO, 10, 2.67f,
+R_LINE_TO, 1.85f, -0.62f,
+R_ARC_TO, 0.89f, 0.89f, 0, 0, 1, 1.11f, 0.54f,
+LINE_TO, 15, 8,
+H_LINE_TO, 5,
+R_LINE_TO, 2.03f, -5.42f,
+R_ARC_TO, 0.89f, 0.89f, 0, 0, 1, 1.11f, -0.54f,
+CLOSE,
+MOVE_TO, 18, 10,
+H_LINE_TO, 2,
+V_LINE_TO, 9,
+R_H_LINE_TO, 16,
+R_V_LINE_TO, 1,
+CLOSE,
+R_MOVE_TO, -4.06f, 7,
+R_ARC_TO, 3.03f, 3.03f, 0, 0, 1, -3.03f, -2.75f,
+R_CUBIC_TO, -0.84f, -0.53f, -1.55f, -0.2f, -1.8f, -0.01f,
+CUBIC_TO, 8.97f, 15.78f, 7.67f, 17, 6.06f, 17,
+CUBIC_TO, 4.37f, 17, 3, 15.65f, 3, 14,
+R_CUBIC_TO, 0, -1.65f, 1.37f, -3, 3.06f, -3,
+R_CUBIC_TO, 1.45f, 0, 2.65f, 0.98f, 2.98f, 2.31f,
+R_ARC_TO, 2.45f, 2.45f, 0, 0, 1, 1.92f, 0.01f,
+ARC_TO, 3.04f, 3.04f, 0, 0, 1, 13.94f, 11,
+CUBIC_TO, 15.63f, 11, 17, 12.35f, 17, 14,
+R_CUBIC_TO, 0, 1.65f, -1.37f, 3, -3.06f, 3,
+CLOSE,
+MOVE_TO, 14, 16,
+R_ARC_TO, 2, 2, 0, 1, 0, 0, -4,
+R_ARC_TO, 2, 2, 0, 0, 0, 0, 4,
+CLOSE,
+R_MOVE_TO, -8, 0,
+R_ARC_TO, 2, 2, 0, 1, 0, 0, -4,
+R_ARC_TO, 2, 2, 0, 0, 0, 0, 4,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/new_tab.icon b/chromium/ui/views/vector_icons/new_tab.icon
new file mode 100644
index 00000000000..51bbe0ecbfd
--- /dev/null
+++ b/chromium/ui/views/vector_icons/new_tab.icon
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4, 2,
+R_H_LINE_TO, 12,
+R_ARC_TO, 2, 2, 0, 0, 1, 2, 2,
+R_V_LINE_TO, 12,
+R_ARC_TO, 2, 2, 0, 0, 1, -2, 2,
+H_LINE_TO, 4,
+R_ARC_TO, 2, 2, 0, 0, 1, -2, -2,
+V_LINE_TO, 4,
+R_ARC_TO, 2, 2, 0, 0, 1, 2, -2,
+CLOSE,
+R_MOVE_TO, 0, 2,
+R_V_LINE_TO, 12,
+R_H_LINE_TO, 12,
+V_LINE_TO, 4,
+H_LINE_TO, 4,
+CLOSE,
+R_MOVE_TO, 4, 0,
+R_H_LINE_TO, 8,
+R_V_LINE_TO, 4,
+R_H_LINE_TO, -6,
+R_ARC_TO, 2, 2, 0, 0, 1, -2, -2,
+V_LINE_TO, 4,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/new_window.icon b/chromium/ui/views/vector_icons/new_window.icon
new file mode 100644
index 00000000000..8d1e690424d
--- /dev/null
+++ b/chromium/ui/views/vector_icons/new_window.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 15, 5,
+R_H_LINE_TO, 3,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, -3,
+R_V_LINE_TO, 3,
+R_H_LINE_TO, -2,
+V_LINE_TO, 7,
+R_H_LINE_TO, -3,
+V_LINE_TO, 5,
+R_H_LINE_TO, 3,
+V_LINE_TO, 2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 3,
+CLOSE,
+R_MOVE_TO, 1, 11,
+R_V_LINE_TO, -4,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 4,
+R_CUBIC_TO, 0, 1, -1, 2, -2, 2,
+H_LINE_TO, 4,
+R_CUBIC_TO, -1, 0, -2, -1, -2, -2,
+V_LINE_TO, 4,
+R_CUBIC_TO, 0, -1, 1, -2, 2, -2,
+R_H_LINE_TO, 4,
+R_V_LINE_TO, 2,
+H_LINE_TO, 4,
+R_V_LINE_TO, 12,
+R_H_LINE_TO, 12,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/open.icon b/chromium/ui/views/vector_icons/open.icon
new file mode 100644
index 00000000000..fa352617a2f
--- /dev/null
+++ b/chromium/ui/views/vector_icons/open.icon
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 6, 4,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 6.5f,
+LINE_TO, 4, 14.5f,
+LINE_TO, 5.5f, 16,
+LINE_TO, 14, 7.5f,
+V_LINE_TO, 14,
+R_H_LINE_TO, 2,
+V_LINE_TO, 4,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/options.icon b/chromium/ui/views/vector_icons/options.icon
new file mode 100644
index 00000000000..fbd0aa537f5
--- /dev/null
+++ b/chromium/ui/views/vector_icons/options.icon
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 14, 10,
+R_ARC_TO, 2, 2, 0, 1, 1, 4, 0,
+ARC_TO, 2, 2, 0, 0, 1, 14, 10,
+CLOSE,
+R_MOVE_TO, -2, 0,
+R_ARC_TO, 2, 2, 0, 1, 1, -4, 0,
+ARC_TO, 2, 2, 0, 0, 1, 12, 10,
+CLOSE,
+R_MOVE_TO, -6, 0,
+R_ARC_TO, 2, 2, 0, 1, 1, -4, 0,
+ARC_TO, 2, 2, 0, 0, 1, 6, 10,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/pin.icon b/chromium/ui/views/vector_icons/pin.icon
new file mode 100644
index 00000000000..24cc87a2cf3
--- /dev/null
+++ b/chromium/ui/views/vector_icons/pin.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 14.8f, 7.76f,
+LINE_TO, 12.24f, 5.2f,
+R_LINE_TO, -5.01f, 5.01f,
+H_LINE_TO, 5.73f,
+LINE_TO, 9.79f, 14.27f,
+V_LINE_TO, 12.77f,
+LINE_TO, 14.8f, 7.76f,
+CLOSE,
+R_MOVE_TO, 3.2f, 0.64f,
+R_LINE_TO, -1.28f, 1.28f,
+R_LINE_TO, -0.64f, -0.64f,
+R_LINE_TO, -4.48f, 4.48f,
+R_V_LINE_TO, 2.56f,
+R_LINE_TO, -1.28f, 1.28f,
+R_LINE_TO, -3.2f, -3.2f,
+LINE_TO, 3.28f, 18,
+H_LINE_TO, 2,
+R_V_LINE_TO, -1.28f,
+R_LINE_TO, 3.84f, -3.84f,
+R_LINE_TO, -3.2f, -3.2f,
+LINE_TO, 3.92f, 8.4f,
+R_H_LINE_TO, 2.56f,
+R_LINE_TO, 4.48f, -4.48f,
+R_LINE_TO, -0.64f, -0.64f,
+LINE_TO, 11.6f, 2,
+LINE_TO, 18, 8.4f,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/radio_button_active.icon b/chromium/ui/views/vector_icons/radio_button_active.icon
index 0533b99ba7e..5f94564ccec 100644
--- a/chromium/ui/views/vector_icons/radio_button_active.icon
+++ b/chromium/ui/views/vector_icons/radio_button_active.icon
@@ -5,5 +5,4 @@
CANVAS_DIMENSIONS, 32,
CIRCLE, 16, 16, 14,
CIRCLE, 16, 16, 11,
-CIRCLE, 16, 16, 7,
-END
+CIRCLE, 16, 16, 7
diff --git a/chromium/ui/views/vector_icons/radio_button_normal.icon b/chromium/ui/views/vector_icons/radio_button_normal.icon
index 62ef2daec82..047257b4759 100644
--- a/chromium/ui/views/vector_icons/radio_button_normal.icon
+++ b/chromium/ui/views/vector_icons/radio_button_normal.icon
@@ -4,5 +4,4 @@
CANVAS_DIMENSIONS, 32,
CIRCLE, 16, 16, 14,
-CIRCLE, 16, 16, 11,
-END
+CIRCLE, 16, 16, 11
diff --git a/chromium/ui/views/vector_icons/submenu_arrow.1x.icon b/chromium/ui/views/vector_icons/submenu_arrow.1x.icon
deleted file mode 100644
index c964eeed576..00000000000
--- a/chromium/ui/views/vector_icons/submenu_arrow.1x.icon
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 8,
-FLIPS_IN_RTL,
-MOVE_TO, 2, 8,
-R_LINE_TO, 5, -4,
-R_LINE_TO, -5, -4,
-R_V_LINE_TO, 8,
-CLOSE,
-END
diff --git a/chromium/ui/views/vector_icons/submenu_arrow.icon b/chromium/ui/views/vector_icons/submenu_arrow.icon
index 2ebf8a3bb8a..9d633095483 100644
--- a/chromium/ui/views/vector_icons/submenu_arrow.icon
+++ b/chromium/ui/views/vector_icons/submenu_arrow.icon
@@ -8,5 +8,12 @@ MOVE_TO, 3, 16,
R_LINE_TO, 11, -8,
LINE_TO, 3, 0,
R_V_LINE_TO, 16,
-CLOSE,
-END
+CLOSE
+
+CANVAS_DIMENSIONS, 8,
+FLIPS_IN_RTL,
+MOVE_TO, 2, 8,
+R_LINE_TO, 5, -4,
+R_LINE_TO, -5, -4,
+R_V_LINE_TO, 8,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/uninstall.icon b/chromium/ui/views/vector_icons/uninstall.icon
new file mode 100644
index 00000000000..4e567278b0d
--- /dev/null
+++ b/chromium/ui/views/vector_icons/uninstall.icon
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 13, 3,
+V_LINE_TO, 2,
+H_LINE_TO, 7,
+R_V_LINE_TO, 1,
+H_LINE_TO, 3,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 1,
+R_V_LINE_TO, 11,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+R_H_LINE_TO, 8,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+V_LINE_TO, 5,
+R_H_LINE_TO, 1,
+V_LINE_TO, 3,
+R_H_LINE_TO, -4,
+CLOSE,
+R_MOVE_TO, 1, 13,
+H_LINE_TO, 6,
+V_LINE_TO, 5,
+R_H_LINE_TO, 8,
+R_V_LINE_TO, 11,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/unpin.icon b/chromium/ui/views/vector_icons/unpin.icon
new file mode 100644
index 00000000000..c8ee6fd29b6
--- /dev/null
+++ b/chromium/ui/views/vector_icons/unpin.icon
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 18, 8.4f,
+R_LINE_TO, -1.28f, 1.28f,
+R_LINE_TO, -0.64f, -0.64f,
+R_LINE_TO, -4.48f, 4.48f,
+R_V_LINE_TO, 2.56f,
+R_LINE_TO, -1.28f, 1.28f,
+R_LINE_TO, -3.2f, -3.2f,
+LINE_TO, 3.28f, 18,
+H_LINE_TO, 2,
+R_V_LINE_TO, -1.28f,
+R_LINE_TO, 3.84f, -3.84f,
+R_LINE_TO, -3.2f, -3.2f,
+LINE_TO, 3.92f, 8.4f,
+R_H_LINE_TO, 2.56f,
+R_LINE_TO, 4.48f, -4.48f,
+R_LINE_TO, -0.64f, -0.64f,
+LINE_TO, 11.6f, 2,
+CLOSE
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index 8568fae0fc1..f544882a25c 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -12,7 +12,6 @@
#include "base/containers/adapters.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -437,9 +436,7 @@ void View::SetPreferredSize(const gfx::Size& size) {
}
void View::SizeToPreferredSize() {
- gfx::Size pref_size = GetPreferredSize();
- if ((pref_size.width() != width()) || (pref_size.height() != height()))
- SetBounds(x(), y(), pref_size.width(), pref_size.height());
+ SetSize(GetPreferredSize());
}
gfx::Size View::GetMinimumSize() const {
diff --git a/chromium/ui/views/view_tracker_unittest.cc b/chromium/ui/views/view_tracker_unittest.cc
index de14208dfd7..ab06814fc79 100644
--- a/chromium/ui/views/view_tracker_unittest.cc
+++ b/chromium/ui/views/view_tracker_unittest.cc
@@ -4,7 +4,6 @@
#include "ui/views/view_tracker.h"
-#include "base/memory/ptr_util.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index 82631bbd6ce..a294b7f2be1 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -323,6 +323,23 @@ TEST_F(ViewTest, LayoutCalledInvalidateAndOriginChanges) {
EXPECT_TRUE(child->did_layout_);
}
+// Tests that SizeToPreferredSize will trigger a Layout if the size has changed
+// or if layout is marked invalid.
+TEST_F(ViewTest, SizeToPreferredSizeInducesLayout) {
+ TestView example_view;
+ example_view.SetPreferredSize(gfx::Size(101, 102));
+ example_view.SizeToPreferredSize();
+ EXPECT_TRUE(example_view.did_layout_);
+
+ example_view.Reset();
+ example_view.SizeToPreferredSize();
+ EXPECT_FALSE(example_view.did_layout_);
+
+ example_view.InvalidateLayout();
+ example_view.SizeToPreferredSize();
+ EXPECT_TRUE(example_view.did_layout_);
+}
+
////////////////////////////////////////////////////////////////////////////////
// OnBoundsChanged
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index 964f1390be0..a64b2cb2551 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -5,7 +5,6 @@
#include "ui/views/views_delegate.h"
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/views/views_touch_selection_controller_factory.h"
#include "ui/views/widget/native_widget_private.h"
diff --git a/chromium/ui/views/views_perftests.cc b/chromium/ui/views/views_perftests.cc
index 65a61183415..6740c887c41 100644
--- a/chromium/ui/views/views_perftests.cc
+++ b/chromium/ui/views/views_perftests.cc
@@ -11,5 +11,6 @@ int main(int argc, char** argv) {
mojo::edk::Init();
return base::LaunchUnitTestsSerially(
argc, argv,
- base::Bind(&views::ViewsTestSuite::Run, base::Unretained(&test_suite)));
+ base::BindOnce(&views::ViewsTestSuite::Run,
+ base::Unretained(&test_suite)));
}
diff --git a/chromium/ui/views/views_test_suite.cc b/chromium/ui/views/views_test_suite.cc
index 82c406c5ea9..44f34e279a4 100644
--- a/chromium/ui/views/views_test_suite.cc
+++ b/chromium/ui/views/views_test_suite.cc
@@ -31,12 +31,14 @@ ViewsTestSuite::~ViewsTestSuite() {}
int ViewsTestSuite::RunTests() {
return base::LaunchUnitTests(
- argc_, argv_, base::Bind(&ViewsTestSuite::Run, base::Unretained(this)));
+ argc_, argv_,
+ base::BindOnce(&ViewsTestSuite::Run, base::Unretained(this)));
}
int ViewsTestSuite::RunTestsSerially() {
return base::LaunchUnitTestsSerially(
- argc_, argv_, base::Bind(&ViewsTestSuite::Run, base::Unretained(this)));
+ argc_, argv_,
+ base::BindOnce(&ViewsTestSuite::Run, base::Unretained(this)));
}
void ViewsTestSuite::Initialize() {
diff --git a/chromium/ui/views/widget/desktop_aura/OWNERS b/chromium/ui/views/widget/desktop_aura/OWNERS
index deec8966b35..9069e120fb6 100644
--- a/chromium/ui/views/widget/desktop_aura/OWNERS
+++ b/chromium/ui/views/widget/desktop_aura/OWNERS
@@ -1,3 +1,2 @@
-# Elliot is the owner of all the X11 stuff.
-per-file *x11*=erg@chromium.org
-per-file window_event_filter*=erg@chromium.org
+per-file *x11*=thomasanderson@chromium.org
+per-file window_event_filter*=thomasanderson@chromium.org
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index 55dcdf780eb..ad0123acabc 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -7,7 +7,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/event_types.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -30,6 +29,7 @@
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform_event.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
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 5158b0d4e37..3a7edcd000f 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
@@ -4,7 +4,6 @@
#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/win/win_util.h"
#include "ui/aura/client/drag_drop_client.h"
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 cde45a41be5..bb391ec3b33 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
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
@@ -348,7 +347,8 @@ void DesktopNativeWidgetAura::OnDesktopWindowTreeHostDestroyed(
}
void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
- native_widget_delegate_->OnNativeWidgetActivationChanged(active);
+ if (!native_widget_delegate_->OnNativeWidgetActivationChanged(active))
+ return;
wm::ActivationClient* activation_client =
wm::GetActivationClient(host_->window());
if (!activation_client)
@@ -432,7 +432,7 @@ void DesktopNativeWidgetAura::InitNativeWidget(
}
host_.reset(desktop_window_tree_host_->AsWindowTreeHost());
}
- desktop_window_tree_host_->Init(content_window_, params);
+ desktop_window_tree_host_->Init(params);
host_->window()->AddChild(content_window_);
host_->window()->SetProperty(kDesktopNativeWidgetAuraKey, this);
@@ -473,6 +473,8 @@ void DesktopNativeWidgetAura::InitNativeWidget(
aura::client::SetCursorClient(host_->window(), cursor_manager_);
}
+ host_->window()->SetName(params.name);
+ content_window_->SetName("DesktopNativeWidgetAura - content window");
desktop_window_tree_host_->OnNativeWidgetCreated(params);
UpdateWindowTransparency();
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 812a37dac77..fc4d17f3285 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
@@ -51,6 +51,8 @@ class FocusManagerEventHandler;
class TooltipManagerAura;
class WindowReorderer;
+// DesktopNativeWidgetAura handles top-level widgets on Windows, Linux, and
+// Chrome OS with mash.
class VIEWS_EXPORT DesktopNativeWidgetAura
: public internal::NativeWidgetPrivate,
public aura::WindowDelegate,
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 0e8bd99e750..e9ddabeeda6 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
@@ -134,6 +134,31 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetNotVisibleOnlyWindowTreeHostShown) {
EXPECT_FALSE(widget.IsVisible());
}
+TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowShowFrameless) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+
+ // Make sure that changing frame type doesn't crash when there's no non-client
+ // view.
+ ASSERT_EQ(nullptr, widget.non_client_view());
+ widget.DebugToggleFrameType();
+ widget.Show();
+
+#if defined(OS_WIN)
+ // On Windows also make sure that handling WM_SYSCOMMAND doesn't crash with
+ // custom frame. Frame type needs to be toggled again if Aero Glass is
+ // disabled.
+ if (widget.ShouldUseNativeFrame())
+ widget.DebugToggleFrameType();
+ SendMessage(widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
+ WM_SYSCOMMAND, SC_RESTORE, 0);
+#endif // OS_WIN
+}
+
// Verify that the cursor state is shared between two native widgets.
TEST_F(DesktopNativeWidgetAuraTest, GlobalCursorState) {
// Create two native widgets, each owning different root windows.
@@ -276,8 +301,8 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetCanBeDestroyedFromNestedLoop) {
base::Closure quit_runloop = run_loop.QuitClosure();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&QuitNestedLoopAndCloseWidget, base::Passed(&widget),
- base::Unretained(&quit_runloop)));
+ base::BindOnce(&QuitNestedLoopAndCloseWidget, std::move(widget),
+ base::Unretained(&quit_runloop)));
run_loop.Run();
}
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 17464aafc78..2822c8e41ef 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -6,6 +6,8 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/memory/protected_memory_cfi.h"
+#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "ui/aura/window.h"
@@ -33,14 +35,22 @@
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
+#include <dlfcn.h>
+
namespace {
// static
-gfx::ICCProfile GetICCProfileFromBestMonitor() {
+gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
gfx::ICCProfile icc_profile;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return icc_profile;
- Atom property = gfx::GetAtom("_ICC_PROFILE");
+ std::string atom_name;
+ if (monitor == 0) {
+ atom_name = "_ICC_PROFILE";
+ } else {
+ atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
+ }
+ Atom property = gfx::GetAtom(atom_name.c_str());
if (property != x11::None) {
Atom prop_type = x11::None;
int prop_format = 0;
@@ -108,7 +118,7 @@ namespace views {
DesktopScreenX11::DesktopScreenX11()
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
- has_xrandr_(false),
+ xrandr_version_(0),
xrandr_event_base_(0),
primary_display_index_(0),
weak_factory_(this) {
@@ -118,12 +128,11 @@ DesktopScreenX11::DesktopScreenX11()
// use the new interface instead of the 1.2 one.
int randr_version_major = 0;
int randr_version_minor = 0;
- has_xrandr_ = XRRQueryVersion(
- xdisplay_, &randr_version_major, &randr_version_minor) &&
- randr_version_major == 1 &&
- randr_version_minor >= 3;
-
- if (has_xrandr_) {
+ if (XRRQueryVersion(xdisplay_, &randr_version_major, &randr_version_minor)) {
+ xrandr_version_ = randr_version_major * 100 + randr_version_minor;
+ }
+ // Need at least xrandr version 1.3.
+ if (xrandr_version_ >= 103) {
int error_base_ignored = 0;
XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
@@ -144,7 +153,7 @@ DesktopScreenX11::DesktopScreenX11()
DesktopScreenX11::~DesktopScreenX11() {
if (views::LinuxUI::instance())
views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
- if (has_xrandr_ && ui::PlatformEventSource::GetInstance())
+ if (xrandr_version_ >= 103 && ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
@@ -297,7 +306,7 @@ DesktopScreenX11::DesktopScreenX11(
const std::vector<display::Display>& test_displays)
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
- has_xrandr_(false),
+ xrandr_version_(0),
xrandr_event_base_(0),
displays_(test_displays),
primary_display_index_(0),
@@ -306,8 +315,16 @@ DesktopScreenX11::DesktopScreenX11(
views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
}
+typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
+typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
+
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
+ g_XRRGetMonitors_ptr;
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
+ g_XRRFreeMonitors_ptr;
+
std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
- DCHECK(has_xrandr_);
+ DCHECK(xrandr_version_ >= 103);
std::vector<display::Display> displays;
gfx::XScopedPtr<
XRRScreenResources,
@@ -318,6 +335,30 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
return GetFallbackDisplayList();
}
+ std::map<RROutput, int> output_to_monitor;
+ if (xrandr_version_ >= 105) {
+ void* xrandr_lib = dlopen(NULL, RTLD_NOW);
+ if (xrandr_lib) {
+ static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
+ &g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
+ dlsym(xrandr_lib, "XRRGetMonitors")));
+ static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
+ &g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
+ dlsym(xrandr_lib, "XRRFreeMonitors")));
+ if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
+ int nmonitors = 0;
+ XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
+ g_XRRGetMonitors_ptr)(xdisplay_, x_root_window_, false, &nmonitors);
+ for (int monitor = 0; monitor < nmonitors; monitor++) {
+ for (int j = 0; j < monitors[monitor].noutput; j++) {
+ output_to_monitor[monitors[monitor].outputs[j]] = monitor;
+ }
+ }
+ base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
+ }
+ }
+ }
+
primary_display_index_ = 0;
RROutput primary_display_id = XRRGetOutputPrimary(xdisplay_, x_root_window_);
@@ -397,10 +438,10 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
if (is_primary_display)
primary_display_index_ = displays.size();
- // TODO(ccameron): Populate this based on this specific display.
- // http://crbug.com/735613
if (!display::Display::HasForceColorProfile()) {
- gfx::ICCProfile icc_profile = GetICCProfileFromBestMonitor();
+ auto monitor_iter = output_to_monitor.find(output_id);
+ gfx::ICCProfile icc_profile = GetICCProfileForMonitor(
+ monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
icc_profile.HistogramDisplay(display.id());
display.set_color_space(icc_profile.GetColorSpace());
}
@@ -424,7 +465,7 @@ void DesktopScreenX11::RestartDelayedConfigurationTask() {
void DesktopScreenX11::UpdateDisplays() {
std::vector<display::Display> old_displays = displays_;
- if (has_xrandr_)
+ if (xrandr_version_ > 103)
SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
else
SetDisplaysInternal(GetFallbackDisplayList());
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 842eb013535..6b7cb73d7f6 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -87,8 +87,8 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
::Display* xdisplay_;
::Window x_root_window_;
- // Whether the x server supports the XRandR extension.
- bool has_xrandr_;
+ // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present.
+ int xrandr_version_;
// The base of the event numbers used to represent XRandr events used in
// decoding events regarding output add/remove.
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 834ab5d2379..437a0294a4d 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
@@ -48,8 +48,7 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
// Sets up resources needed before the WindowEventDispatcher has been created.
// It is expected this calls InitHost() on the WindowTreeHost.
- virtual void Init(aura::Window* content_window,
- const Widget::InitParams& params) = 0;
+ virtual void Init(const Widget::InitParams& params) = 0;
// Invoked once the DesktopNativeWidgetAura has been created.
virtual void OnNativeWidgetCreated(const Widget::InitParams& params) = 0;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
new file mode 100644
index 00000000000..97b54ace8b5
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -0,0 +1,426 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/transient_window_client.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/views/corewm/tooltip_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/window/native_frame_view.h"
+#include "ui/wm/core/window_util.h"
+
+namespace views {
+
+DesktopWindowTreeHostPlatform::DesktopWindowTreeHostPlatform(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura)
+ : native_widget_delegate_(native_widget_delegate),
+ desktop_native_widget_aura_(desktop_native_widget_aura) {}
+
+DesktopWindowTreeHostPlatform::~DesktopWindowTreeHostPlatform() {
+ DCHECK(got_on_closed_);
+ desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
+ DestroyDispatcher();
+}
+
+void DesktopWindowTreeHostPlatform::SetBoundsInDIP(
+ const gfx::Rect& bounds_in_dip) {
+ DCHECK_NE(0, device_scale_factor());
+ SetBoundsInPixels(
+ gfx::ConvertRectToPixel(device_scale_factor(), bounds_in_dip));
+}
+
+void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
+ CreateAndSetDefaultPlatformWindow();
+ // TODO(sky): this should be |params.force_software_compositing|, figure out
+ // why it has to be true now.
+ const bool use_software_compositing = true;
+ CreateCompositor(viz::FrameSinkId(), use_software_compositing);
+ aura::WindowTreeHost::OnAcceleratedWidgetAvailable();
+ InitHost();
+ if (!params.bounds.IsEmpty())
+ SetBoundsInDIP(params.bounds);
+ window()->Show();
+}
+
+void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
+ const Widget::InitParams& params) {
+ native_widget_delegate_->OnNativeWidgetCreated(true);
+}
+
+void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
+
+void DesktopWindowTreeHostPlatform::OnActiveWindowChanged(bool active) {}
+
+std::unique_ptr<corewm::Tooltip>
+DesktopWindowTreeHostPlatform::CreateTooltip() {
+ return std::make_unique<corewm::TooltipAura>();
+}
+
+std::unique_ptr<aura::client::DragDropClient>
+DesktopWindowTreeHostPlatform::CreateDragDropClient(
+ DesktopNativeCursorManager* cursor_manager) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return nullptr;
+}
+
+void DesktopWindowTreeHostPlatform::Close() {
+ if (waiting_for_close_now_)
+ return;
+
+ // Hide while waiting for the close.
+ platform_window()->Hide();
+
+ waiting_for_close_now_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&DesktopWindowTreeHostPlatform::CloseNow,
+ weak_factory_.GetWeakPtr()));
+}
+
+void DesktopWindowTreeHostPlatform::CloseNow() {
+ auto weak_ref = weak_factory_.GetWeakPtr();
+ // Deleting the PlatformWindow may not result in OnClosed() being called, if
+ // not behave as though it was.
+ SetPlatformWindow(nullptr);
+ if (!weak_ref || got_on_closed_)
+ return;
+
+ got_on_closed_ = true;
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+aura::WindowTreeHost* DesktopWindowTreeHostPlatform::AsWindowTreeHost() {
+ return this;
+}
+
+void DesktopWindowTreeHostPlatform::ShowWindowWithState(
+ ui::WindowShowState show_state) {
+ if (compositor()) {
+ platform_window()->Show();
+ compositor()->SetVisible(true);
+ }
+
+ switch (show_state) {
+ case ui::SHOW_STATE_MAXIMIZED:
+ platform_window()->Maximize();
+ break;
+ case ui::SHOW_STATE_MINIMIZED:
+ platform_window()->Minimize();
+ break;
+ case ui::SHOW_STATE_FULLSCREEN:
+ // TODO(sky): this isn't necessarily the same as explicitly setting
+ // fullscreen.
+ platform_window()->ToggleFullscreen();
+ break;
+ default:
+ break;
+ }
+
+ if (native_widget_delegate_->CanActivate()) {
+ if (show_state != ui::SHOW_STATE_INACTIVE)
+ Activate();
+
+ // SetInitialFocus() should be always be called, even for
+ // SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
+ // do the right thing.
+ // Activate() might fail if the window is non-activatable. In this case, we
+ // should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
+ // focused view from getting focused. See https://crbug.com/515594 for
+ // example.
+ native_widget_delegate_->SetInitialFocus(
+ IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
+ }
+}
+
+void DesktopWindowTreeHostPlatform::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ // TODO: support |restored_bounds|.
+ ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
+}
+
+bool DesktopWindowTreeHostPlatform::IsVisible() const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return true;
+}
+
+void DesktopWindowTreeHostPlatform::SetSize(const gfx::Size& size) {
+ gfx::Rect screen_bounds =
+ gfx::ConvertRectToDIP(device_scale_factor(), GetBoundsInPixels());
+ screen_bounds.set_size(size);
+ SetBoundsInDIP(screen_bounds);
+}
+
+void DesktopWindowTreeHostPlatform::StackAbove(aura::Window* window) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::StackAtTop() {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
+ gfx::Rect bounds_to_center_in = GetWorkAreaBoundsInScreen();
+
+ // If there is a transient parent and it fits |size|, then center over it.
+ aura::Window* content_window = desktop_native_widget_aura_->content_window();
+ if (wm::GetTransientParent(content_window)) {
+ gfx::Rect transient_parent_bounds =
+ wm::GetTransientParent(content_window)->GetBoundsInScreen();
+ if (transient_parent_bounds.height() >= size.height() &&
+ transient_parent_bounds.width() >= size.width()) {
+ bounds_to_center_in = transient_parent_bounds;
+ }
+ }
+
+ gfx::Rect resulting_bounds(bounds_to_center_in);
+ resulting_bounds.ClampToCenteredSize(size);
+ SetBoundsInDIP(resulting_bounds);
+}
+
+void DesktopWindowTreeHostPlatform::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ NOTIMPLEMENTED_LOG_ONCE();
+ *bounds = gfx::Rect(0, 0, 640, 840);
+ *show_state = ui::SHOW_STATE_NORMAL;
+}
+
+gfx::Rect DesktopWindowTreeHostPlatform::GetWindowBoundsInScreen() const {
+ gfx::Rect bounds =
+ gfx::ConvertRectToDIP(device_scale_factor(), GetBoundsInPixels());
+ bounds += display::Screen::GetScreen()
+ ->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
+ .bounds()
+ .OffsetFromOrigin();
+ return bounds;
+}
+
+gfx::Rect DesktopWindowTreeHostPlatform::GetClientAreaBoundsInScreen() const {
+ // View-to-screen coordinate system transformations depend on this returning
+ // the full window bounds, for example View::ConvertPointToScreen().
+ return GetWindowBoundsInScreen();
+}
+
+gfx::Rect DesktopWindowTreeHostPlatform::GetRestoredBounds() const {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return gfx::Rect(0, 0, 640, 840);
+}
+
+std::string DesktopWindowTreeHostPlatform::GetWorkspace() const {
+ return std::string();
+}
+
+gfx::Rect DesktopWindowTreeHostPlatform::GetWorkAreaBoundsInScreen() const {
+ // TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
+ return display::Screen::GetScreen()
+ ->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
+ .work_area();
+}
+
+void DesktopWindowTreeHostPlatform::SetShape(
+ std::unique_ptr<Widget::ShapeRects> native_shape) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::Activate() {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::Deactivate() {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::IsActive() const {
+ return is_active_;
+}
+
+void DesktopWindowTreeHostPlatform::Maximize() {
+ platform_window()->Maximize();
+}
+
+void DesktopWindowTreeHostPlatform::Minimize() {
+ platform_window()->Minimize();
+}
+
+void DesktopWindowTreeHostPlatform::Restore() {
+ platform_window()->Restore();
+}
+
+bool DesktopWindowTreeHostPlatform::IsMaximized() const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::IsMinimized() const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::HasCapture() const {
+ return platform_window()->HasCapture();
+}
+
+void DesktopWindowTreeHostPlatform::SetAlwaysOnTop(bool always_on_top) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::IsAlwaysOnTop() const {
+ // TODO: needs PlatformWindow support.
+ return false;
+}
+
+void DesktopWindowTreeHostPlatform::SetVisibleOnAllWorkspaces(
+ bool always_visible) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::IsVisibleOnAllWorkspaces() const {
+ // TODO: needs PlatformWindow support.
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::SetWindowTitle(
+ const base::string16& title) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void DesktopWindowTreeHostPlatform::ClearNativeFocus() {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+Widget::MoveLoopResult DesktopWindowTreeHostPlatform::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return Widget::MOVE_LOOP_CANCELED;
+}
+
+void DesktopWindowTreeHostPlatform::EndMoveLoop() {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+NonClientFrameView* DesktopWindowTreeHostPlatform::CreateNonClientFrameView() {
+ return ShouldUseNativeFrame() ? new NativeFrameView(GetWidget()) : nullptr;
+}
+
+bool DesktopWindowTreeHostPlatform::ShouldUseNativeFrame() const {
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::ShouldWindowContentsBeTransparent() const {
+ return false;
+}
+
+void DesktopWindowTreeHostPlatform::FrameTypeChanged() {}
+
+void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::IsFullscreen() const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void DesktopWindowTreeHostPlatform::SetOpacity(float opacity) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::SetWindowIcons(
+ const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::InitModalType(ui::ModalType modal_type) {
+ // TODO: needs PlatformWindow support (alternatively, remove as
+ // DesktopWindowTreeHostX11 doesn't support at all).
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopWindowTreeHostPlatform::FlashFrame(bool flash_frame) {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::IsAnimatingClosed() const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::IsTranslucentWindowOpacitySupported()
+ const {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void DesktopWindowTreeHostPlatform::SizeConstraintsChanged() {
+ // TODO: needs PlatformWindow support.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool DesktopWindowTreeHostPlatform::ShouldUpdateWindowTransparency() const {
+ return false;
+}
+
+bool DesktopWindowTreeHostPlatform::ShouldUseDesktopNativeCursorManager()
+ const {
+ return true;
+}
+
+bool DesktopWindowTreeHostPlatform::ShouldCreateVisibilityController() const {
+ return true;
+}
+
+void DesktopWindowTreeHostPlatform::OnClosed() {
+ got_on_closed_ = true;
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+void DesktopWindowTreeHostPlatform::OnCloseRequest() {
+ GetWidget()->Close();
+}
+
+void DesktopWindowTreeHostPlatform::OnActivationChanged(bool active) {
+ is_active_ = active;
+ aura::WindowTreeHostPlatform::OnActivationChanged(active);
+ desktop_native_widget_aura_->HandleActivationChanged(active);
+}
+
+Widget* DesktopWindowTreeHostPlatform::GetWidget() {
+ return native_widget_delegate_->AsWidget();
+}
+
+} // namespace views
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
new file mode 100644
index 00000000000..e9bc864128e
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -0,0 +1,116 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_
+
+#include "base/memory/weak_ptr.h"
+#include "ui/aura/window_tree_host_platform.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+
+namespace views {
+
+class VIEWS_EXPORT DesktopWindowTreeHostPlatform
+ : public aura::WindowTreeHostPlatform,
+ public DesktopWindowTreeHost {
+ public:
+ DesktopWindowTreeHostPlatform(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura);
+ ~DesktopWindowTreeHostPlatform() override;
+
+ void SetBoundsInDIP(const gfx::Rect& bounds_in_dip);
+
+ // DesktopWindowTreeHost:
+ void Init(const Widget::InitParams& params) override;
+ void OnNativeWidgetCreated(const Widget::InitParams& params) override;
+ 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;
+ void Close() override;
+ void CloseNow() override;
+ aura::WindowTreeHost* AsWindowTreeHost() override;
+ void ShowWindowWithState(ui::WindowShowState show_state) override;
+ void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
+ bool IsVisible() const override;
+ void SetSize(const gfx::Size& size) override;
+ void StackAbove(aura::Window* window) override;
+ void StackAtTop() override;
+ void CenterWindow(const gfx::Size& size) override;
+ void GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const override;
+ gfx::Rect GetWindowBoundsInScreen() const override;
+ gfx::Rect GetClientAreaBoundsInScreen() const override;
+ gfx::Rect GetRestoredBounds() const override;
+ std::string GetWorkspace() const override;
+ gfx::Rect GetWorkAreaBoundsInScreen() const override;
+ void SetShape(std::unique_ptr<Widget::ShapeRects> native_shape) override;
+ void Activate() override;
+ void Deactivate() override;
+ bool IsActive() const override;
+ void Maximize() override;
+ void Minimize() override;
+ void Restore() override;
+ bool IsMaximized() const override;
+ bool IsMinimized() const override;
+ bool HasCapture() const override;
+ void SetAlwaysOnTop(bool always_on_top) override;
+ bool IsAlwaysOnTop() const override;
+ void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
+ bool SetWindowTitle(const base::string16& title) override;
+ void ClearNativeFocus() override;
+ Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) override;
+ void EndMoveLoop() override;
+ void SetVisibilityChangedAnimationsEnabled(bool value) override;
+ NonClientFrameView* CreateNonClientFrameView() override;
+ bool ShouldUseNativeFrame() const override;
+ bool ShouldWindowContentsBeTransparent() const override;
+ void FrameTypeChanged() override;
+ void SetFullscreen(bool fullscreen) override;
+ bool IsFullscreen() const override;
+ void SetOpacity(float opacity) override;
+ void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) override;
+ void InitModalType(ui::ModalType modal_type) override;
+ void FlashFrame(bool flash_frame) override;
+ bool IsAnimatingClosed() const override;
+ bool IsTranslucentWindowOpacitySupported() const override;
+ void SizeConstraintsChanged() override;
+ bool ShouldUpdateWindowTransparency() const override;
+ bool ShouldUseDesktopNativeCursorManager() const override;
+ bool ShouldCreateVisibilityController() const override;
+
+ // WindowTreeHostPlatform:
+ void OnClosed() override;
+ void OnCloseRequest() override;
+ void OnActivationChanged(bool active) override;
+
+ private:
+ Widget* GetWidget();
+
+ internal::NativeWidgetDelegate* const native_widget_delegate_;
+ DesktopNativeWidgetAura* const desktop_native_widget_aura_;
+
+ // Set to true when Close() is called.
+ bool waiting_for_close_now_ = false;
+
+ bool got_on_closed_ = false;
+
+ bool is_active_ = false;
+
+ base::WeakPtrFactory<DesktopWindowTreeHostPlatform> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostPlatform);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_
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 19f103c0385..c8f868bf416 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
@@ -81,7 +81,6 @@ DesktopWindowTreeHostWin::DesktopWindowTreeHostWin(
: message_handler_(new HWNDMessageHandler(this)),
native_widget_delegate_(native_widget_delegate),
desktop_native_widget_aura_(desktop_native_widget_aura),
- content_window_(NULL),
drag_drop_client_(NULL),
should_animate_window_close_(false),
pending_close_(false),
@@ -90,7 +89,6 @@ DesktopWindowTreeHostWin::DesktopWindowTreeHostWin(
}
DesktopWindowTreeHostWin::~DesktopWindowTreeHostWin() {
- // WARNING: |content_window_| has been destroyed by the time we get here.
desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
DestroyDispatcher();
}
@@ -108,16 +106,13 @@ aura::Window* DesktopWindowTreeHostWin::GetContentWindowForHWND(HWND hwnd) {
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostWin, DesktopWindowTreeHost implementation:
-void DesktopWindowTreeHostWin::Init(aura::Window* content_window,
- const Widget::InitParams& params) {
- // TODO(beng): SetInitParams().
- content_window_ = content_window;
+void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) {
wants_mouse_events_when_inactive_ = params.wants_mouse_events_when_inactive;
- wm::SetAnimationHost(content_window_, this);
+ wm::SetAnimationHost(content_window(), this);
if (params.type == Widget::InitParams::TYPE_WINDOW &&
!params.remove_standard_frame)
- content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
+ content_window()->SetProperty(aura::client::kAnimationsDisabledKey, true);
ConfigureWindowStyles(message_handler_.get(), params,
GetWidget()->widget_delegate(),
@@ -148,12 +143,12 @@ void DesktopWindowTreeHostWin::OnNativeWidgetCreated(
if (cursor_client)
is_cursor_visible_ = cursor_client->IsCursorVisible();
- window()->SetProperty(kContentWindowForRootWindow, content_window_);
+ window()->SetProperty(kContentWindowForRootWindow, content_window());
window()->SetProperty(kDesktopWindowTreeHostKey, this);
should_animate_window_close_ =
- content_window_->type() != aura::client::WINDOW_TYPE_NORMAL &&
- !wm::WindowAnimationsDisabled(content_window_);
+ content_window()->type() != aura::client::WINDOW_TYPE_NORMAL &&
+ !wm::WindowAnimationsDisabled(content_window());
// TODO this is not invoked *after* Init(), but should be ok.
SetWindowTransparency();
@@ -181,7 +176,7 @@ void DesktopWindowTreeHostWin::Close() {
if (should_animate_window_close_) {
pending_close_ = true;
const bool is_animating =
- content_window_->layer()->GetAnimator()->IsAnimatingProperty(
+ content_window()->layer()->GetAnimator()->IsAnimatingProperty(
ui::LayerAnimationElement::VISIBILITY);
// Animation may not start for a number of reasons.
if (!is_animating)
@@ -401,7 +396,7 @@ void DesktopWindowTreeHostWin::EndMoveLoop() {
void DesktopWindowTreeHostWin::SetVisibilityChangedAnimationsEnabled(
bool value) {
message_handler_->SetVisibilityChangedAnimationsEnabled(value);
- content_window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
+ content_window()->SetProperty(aura::client::kAnimationsDisabledKey, !value);
}
NonClientFrameView* DesktopWindowTreeHostWin::CreateNonClientFrameView() {
@@ -434,10 +429,10 @@ void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) {
// TODO(sky): workaround for ScopedFullscreenVisibility showing window
// directly. Instead of this should listen for visibility changes and then
// update window.
- if (message_handler_->IsVisible() && !content_window_->TargetVisibility()) {
+ if (message_handler_->IsVisible() && !content_window()->TargetVisibility()) {
if (compositor())
compositor()->SetVisible(true);
- content_window_->Show();
+ content_window()->Show();
}
SetWindowTransparency();
}
@@ -447,7 +442,7 @@ bool DesktopWindowTreeHostWin::IsFullscreen() const {
}
void DesktopWindowTreeHostWin::SetOpacity(float opacity) {
- content_window_->layer()->SetOpacity(opacity);
+ content_window()->layer()->SetOpacity(opacity);
}
void DesktopWindowTreeHostWin::SetWindowIcons(
@@ -577,6 +572,10 @@ void DesktopWindowTreeHostWin::ReleaseSystemKeyEventCapture() {
keyboard_hook_.reset();
}
+bool DesktopWindowTreeHostWin::IsKeyLocked(int native_key_code) {
+ return keyboard_hook_ && keyboard_hook_->IsKeyLocked(native_key_code);
+}
+
void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) {
ui::CursorLoaderWin cursor_loader;
cursor_loader.SetPlatformCursor(&cursor);
@@ -727,7 +726,8 @@ gfx::Size DesktopWindowTreeHostWin::DIPToScreenSize(
}
void DesktopWindowTreeHostWin::ResetWindowControls() {
- GetWidget()->non_client_view()->ResetWindowControls();
+ if (GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->ResetWindowControls();
}
gfx::NativeViewAccessible DesktopWindowTreeHostWin::GetNativeViewAccessible() {
@@ -845,7 +845,8 @@ void DesktopWindowTreeHostWin::HandleFrameChanged() {
CheckForMonitorChange();
SetWindowTransparency();
// Replace the frame and layout the contents.
- GetWidget()->non_client_view()->UpdateFrame();
+ if (GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->UpdateFrame();
}
void DesktopWindowTreeHostWin::HandleNativeFocus(HWND last_focused_window) {
@@ -856,9 +857,9 @@ void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
// TODO(beng): inform the native_widget_delegate_.
}
-bool DesktopWindowTreeHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
- SendEventToSink(const_cast<ui::MouseEvent*>(&event));
- return event.handled();
+bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
+ SendEventToSink(event);
+ return event->handled();
}
bool DesktopWindowTreeHostWin::HandlePointerEvent(ui::PointerEvent* event) {
@@ -870,8 +871,7 @@ void DesktopWindowTreeHostWin::HandleKeyEvent(ui::KeyEvent* event) {
SendEventToSink(event);
}
-void DesktopWindowTreeHostWin::HandleTouchEvent(
- const ui::TouchEvent& event) {
+void DesktopWindowTreeHostWin::HandleTouchEvent(ui::TouchEvent* event) {
// HWNDMessageHandler asynchronously processes touch events. Because of this
// it's possible for the aura::WindowEventDispatcher to have been destroyed
// by the time we attempt to process them.
@@ -885,10 +885,10 @@ void DesktopWindowTreeHostWin::HandleTouchEvent(
DesktopWindowTreeHostWin* target =
host->window()->GetProperty(kDesktopWindowTreeHostKey);
if (target && target->HasCapture() && target != this) {
- POINT target_location(event.location().ToPOINT());
+ POINT target_location(event->location().ToPOINT());
ClientToScreen(GetHWND(), &target_location);
ScreenToClient(target->GetHWND(), &target_location);
- ui::TouchEvent target_event(event, static_cast<View*>(NULL),
+ ui::TouchEvent target_event(*event, static_cast<View*>(NULL),
static_cast<View*>(NULL));
target_event.set_location(gfx::Point(target_location));
target_event.set_root_location(target_event.location());
@@ -896,7 +896,7 @@ void DesktopWindowTreeHostWin::HandleTouchEvent(
return;
}
}
- SendEventToSink(const_cast<ui::TouchEvent*>(&event));
+ SendEventToSink(event);
}
bool DesktopWindowTreeHostWin::HandleIMEMessage(UINT message,
@@ -949,10 +949,14 @@ void DesktopWindowTreeHostWin::PostHandleMSG(UINT message,
LPARAM l_param) {
}
-bool DesktopWindowTreeHostWin::HandleScrollEvent(
- const ui::ScrollEvent& event) {
- SendEventToSink(const_cast<ui::ScrollEvent*>(&event));
- return event.handled();
+bool DesktopWindowTreeHostWin::HandleScrollEvent(ui::ScrollEvent* event) {
+ SendEventToSink(event);
+ return event->handled();
+}
+
+bool DesktopWindowTreeHostWin::HandleGestureEvent(ui::GestureEvent* event) {
+ SendEventToSink(event);
+ return event->handled();
}
void DesktopWindowTreeHostWin::HandleWindowSizeChanging() {
@@ -965,16 +969,18 @@ void DesktopWindowTreeHostWin::HandleWindowSizeUnchanged() {
// changed (can occur on Windows 10 when snapping a window to the side of
// the screen). In that case do a resize to the current size to reenable
// swaps.
- if (compositor()) {
- compositor()->SetScaleAndSize(
- compositor()->device_scale_factor(),
- message_handler_->GetClientAreaBounds().size(),
- window()->GetLocalSurfaceId());
- }
+ if (compositor())
+ compositor()->ReenableSwap();
}
void DesktopWindowTreeHostWin::HandleWindowScaleFactorChanged(
float window_scale_factor) {
+ // TODO(ccameron): This will violate surface invariants, and is insane.
+ // Shouldn't the scale factor and window pixel size changes be sent
+ // atomically? And how does this interact with updates to display::Display?
+ // Should we expect the display::Display to be updated before this? If so,
+ // why can't we use the DisplayObserver that the base WindowTreeHost is
+ // using?
if (compositor()) {
compositor()->SetScaleAndSize(
window_scale_factor, message_handler_->GetClientAreaBounds().size(),
@@ -1002,7 +1008,7 @@ void DesktopWindowTreeHostWin::SetWindowTransparency() {
compositor()->SetBackgroundColor(transparent ? SK_ColorTRANSPARENT
: SK_ColorWHITE);
window()->SetTransparent(transparent);
- content_window_->SetTransparent(transparent);
+ content_window()->SetTransparent(transparent);
}
bool DesktopWindowTreeHostWin::IsModalWindowActive() const {
@@ -1031,6 +1037,10 @@ void DesktopWindowTreeHostWin::CheckForMonitorChange() {
OnHostDisplayChanged();
}
+aura::Window* DesktopWindowTreeHostWin::content_window() {
+ return desktop_native_widget_aura_->content_window();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHost, public:
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 732f492c102..4120d3ae63f 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
@@ -56,8 +56,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
protected:
// Overridden from DesktopWindowTreeHost:
- void Init(aura::Window* content_window,
- const Widget::InitParams& params) override;
+ void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
void OnActiveWindowChanged(bool active) override;
void OnWidgetInitDone() override;
@@ -134,6 +133,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
bool CaptureSystemKeyEventsImpl(
base::Optional<base::flat_set<int>> keys_codes) override;
void ReleaseSystemKeyEventCapture() override;
+ bool IsKeyLocked(int native_key_code) override;
void SetCursorNative(gfx::NativeCursor cursor) override;
void OnCursorVisibilityChangedNative(bool show) override;
void MoveCursorToScreenLocationInPixels(
@@ -193,10 +193,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void HandleFrameChanged() override;
void HandleNativeFocus(HWND last_focused_window) override;
void HandleNativeBlur(HWND focused_window) override;
- bool HandleMouseEvent(const ui::MouseEvent& event) override;
+ bool HandleMouseEvent(ui::MouseEvent* event) override;
bool HandlePointerEvent(ui::PointerEvent* event) override;
void HandleKeyEvent(ui::KeyEvent* event) override;
- void HandleTouchEvent(const ui::TouchEvent& event) override;
+ void HandleTouchEvent(ui::TouchEvent* event) override;
bool HandleIMEMessage(UINT message,
WPARAM w_param,
LPARAM l_param,
@@ -213,7 +213,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
LPARAM l_param,
LRESULT* result) override;
void PostHandleMSG(UINT message, WPARAM w_param, LPARAM l_param) override;
- bool HandleScrollEvent(const ui::ScrollEvent& event) override;
+ bool HandleScrollEvent(ui::ScrollEvent* event) override;
+ bool HandleGestureEvent(ui::GestureEvent* event) override;
void HandleWindowSizeChanging() override;
void HandleWindowSizeUnchanged() override;
void HandleWindowScaleFactorChanged(float window_scale_factor) override;
@@ -232,6 +233,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
// has changed, and, if so, inform the aura::WindowTreeHost.
void CheckForMonitorChange();
+ // Accessor for DesktopNativeWidgetAura::content_window().
+ aura::Window* content_window();
+
HMONITOR last_monitor_from_window_ = nullptr;
std::unique_ptr<HWNDMessageHandler> message_handler_;
@@ -243,8 +247,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
DesktopNativeWidgetAura* desktop_native_widget_aura_;
- aura::Window* content_window_;
-
// Owned by DesktopNativeWidgetAura.
DesktopDragDropClientWin* drag_drop_client_;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index f8550833ee6..806360dbc69 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -148,7 +148,6 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
drag_drop_client_(NULL),
native_widget_delegate_(native_widget_delegate),
desktop_native_widget_aura_(desktop_native_widget_aura),
- content_window_(NULL),
window_parent_(NULL),
custom_window_shape_(false),
urgency_hint_set_(false),
@@ -388,13 +387,11 @@ void DesktopWindowTreeHostX11::CleanUpWindowList(
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
-void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
- const Widget::InitParams& params) {
- content_window_ = content_window;
+void DesktopWindowTreeHostX11::Init(const Widget::InitParams& params) {
activatable_ = (params.activatable == Widget::InitParams::ACTIVATABLE_YES);
if (params.type == Widget::InitParams::TYPE_WINDOW)
- content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
+ content_window()->SetProperty(aura::client::kAnimationsDisabledKey, true);
// TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
// whether we should be proxying requests to another DRWHL.
@@ -414,7 +411,7 @@ void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
const Widget::InitParams& params) {
- window()->SetProperty(kViewsWindowForRootWindow, content_window_);
+ window()->SetProperty(kViewsWindowForRootWindow, content_window());
window()->SetProperty(kHostForRootWindow, this);
// Ensure that the X11DesktopHandler exists so that it tracks create/destroy
@@ -518,7 +515,7 @@ aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
void DesktopWindowTreeHostX11::ShowWindowWithState(
ui::WindowShowState show_state) {
if (compositor())
- compositor()->SetVisible(true);
+ SetVisible(true);
if (!IsVisible() || !window_mapped_in_server_)
MapWindow(show_state);
@@ -605,9 +602,9 @@ void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
// If |window_|'s transient parent bounds are big enough to contain |size|,
// use them instead.
- if (wm::GetTransientParent(content_window_)) {
+ if (wm::GetTransientParent(content_window())) {
gfx::Rect transient_parent_rect =
- wm::GetTransientParent(content_window_)->GetBoundsInScreen();
+ wm::GetTransientParent(content_window())->GetBoundsInScreen();
if (transient_parent_rect.height() >= size.height() &&
transient_parent_rect.width() >= size.width()) {
parent_bounds_in_pixels = ToPixelRect(transient_parent_rect);
@@ -875,6 +872,13 @@ bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
return is_always_on_top_;
}
+void DesktopWindowTreeHostX11::SetVisible(bool visible) {
+ if (compositor())
+ compositor()->SetVisible(visible);
+ if (IsVisible() != visible)
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
+}
+
void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
ui::SetWMSpecState(xwindow_, always_visible,
gfx::GetAtom("_NET_WM_STATE_STICKY"), x11::None);
@@ -932,12 +936,13 @@ bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
void DesktopWindowTreeHostX11::ClearNativeFocus() {
// This method is weird and misnamed. Instead of clearing the native focus,
- // it sets the focus to our |content_window_|, which will trigger a cascade
+ // it sets the focus to our content_window(), which will trigger a cascade
// of focus changes into views.
- if (content_window_ && aura::client::GetFocusClient(content_window_) &&
- content_window_->Contains(
- aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
- aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
+ if (content_window() && aura::client::GetFocusClient(content_window()) &&
+ content_window()->Contains(
+ aura::client::GetFocusClient(content_window())->GetFocusedWindow())) {
+ aura::client::GetFocusClient(content_window())
+ ->FocusWindow(content_window());
}
}
@@ -948,7 +953,7 @@ Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
wm::WindowMoveSource window_move_source =
source == Widget::MOVE_LOOP_SOURCE_MOUSE ? wm::WINDOW_MOVE_SOURCE_MOUSE
: wm::WINDOW_MOVE_SOURCE_TOUCH;
- if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
+ if (x11_window_move_client_->RunMoveLoop(content_window(), drag_offset,
window_move_source) ==
wm::MOVE_SUCCESSFUL)
return Widget::MOVE_LOOP_SUCCESSFUL;
@@ -1179,15 +1184,14 @@ gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
void DesktopWindowTreeHostX11::ShowImpl() {
ShowWindowWithState(ui::SHOW_STATE_NORMAL);
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
}
void DesktopWindowTreeHostX11::HideImpl() {
if (IsVisible()) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
window_mapped_in_client_ = false;
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
}
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
}
gfx::Rect DesktopWindowTreeHostX11::GetBoundsInPixels() const {
@@ -1310,6 +1314,10 @@ void DesktopWindowTreeHostX11::ReleaseSystemKeyEventCapture() {
keyboard_hook_.reset();
}
+bool DesktopWindowTreeHostX11::IsKeyLocked(int native_key_code) {
+ return keyboard_hook_ && keyboard_hook_->IsKeyLocked(native_key_code);
+}
+
void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
XDefineCursor(xdisplay_, xwindow_, cursor.platform());
}
@@ -1628,11 +1636,11 @@ void DesktopWindowTreeHostX11::OnWMStateUpdated() {
// minimized.
if (is_minimized != was_minimized) {
if (is_minimized) {
- compositor()->SetVisible(false);
- content_window_->Hide();
+ SetVisible(false);
+ content_window()->Hide();
} else {
- content_window_->Show();
- compositor()->SetVisible(true);
+ content_window()->Show();
+ SetVisible(true);
}
}
@@ -1759,10 +1767,10 @@ void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
// events on the ash desktop are clicking in what Windows considers to be a
// non client area.) Likewise, we won't want to do the following in any
// WindowTreeHost that hosts ash.
- if (content_window_ && content_window_->delegate()) {
+ if (content_window() && content_window()->delegate()) {
int flags = event->flags();
int hit_test_code =
- content_window_->delegate()->GetNonClientComponent(event->location());
+ content_window()->delegate()->GetNonClientComponent(event->location());
if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
flags |= ui::EF_IS_NON_CLIENT;
event->set_flags(flags);
@@ -1927,7 +1935,7 @@ void DesktopWindowTreeHostX11::SetWindowTransparency() {
compositor()->SetBackgroundColor(use_argb_visual_ ? SK_ColorTRANSPARENT
: SK_ColorWHITE);
window()->SetTransparent(use_argb_visual_);
- content_window_->SetTransparent(use_argb_visual_);
+ content_window()->SetTransparent(use_argb_visual_);
}
void DesktopWindowTreeHostX11::Relayout() {
@@ -2338,6 +2346,10 @@ void DesktopWindowTreeHostX11::RestartDelayedResizeTask() {
FROM_HERE, delayed_resize_task_.callback());
}
+aura::Window* DesktopWindowTreeHostX11::content_window() {
+ return desktop_native_widget_aura_->content_window();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHost, public:
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 021a1d9ad2b..79d677baa9f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -51,7 +51,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
DesktopNativeWidgetAura* desktop_native_widget_aura);
~DesktopWindowTreeHostX11() override;
- // A way of converting an X11 |xid| host window into a |content_window_|.
+ // A way of converting an X11 |xid| host window into the content_window()
+ // of the associated DesktopNativeWidgetAura.
static aura::Window* GetContentWindowForXID(XID xid);
// A way of converting an X11 |xid| host window into this object.
@@ -88,8 +89,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
protected:
// Overridden from DesktopWindowTreeHost:
- void Init(aura::Window* content_window,
- const Widget::InitParams& params) override;
+ void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
void OnWidgetInitDone() override;
void OnActiveWindowChanged(bool active) override;
@@ -167,6 +167,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
bool CaptureSystemKeyEventsImpl(
base::Optional<base::flat_set<int>> keys_codes) override;
void ReleaseSystemKeyEventCapture() override;
+ bool IsKeyLocked(int native_key_code) override;
void SetCursorNative(gfx::NativeCursor cursor) override;
void MoveCursorToScreenLocationInPixels(
const gfx::Point& location_in_pixels) override;
@@ -188,7 +189,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// initialization related to talking to the X11 server.
void InitX11Window(const Widget::InitParams& params);
- // Creates an aura::WindowEventDispatcher to contain the |content_window|,
+ // Creates an aura::WindowEventDispatcher to contain the content_window()
// along with all aura client objects that direct behavior.
aura::WindowEventDispatcher* InitDispatcher(const Widget::InitParams& params);
@@ -282,6 +283,12 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// the queue) and adds it back at the end of the queue.
void RestartDelayedResizeTask();
+ // Set visibility and fire OnNativeWidgetVisibilityChanged() if it changed.
+ void SetVisible(bool visible);
+
+ // Accessor for DesktopNativeWidgetAura::content_window().
+ aura::Window* content_window();
+
// X11 things
// The display and the native X window hosting the root window.
XDisplay* xdisplay_;
@@ -352,8 +359,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
DesktopNativeWidgetAura* desktop_native_widget_aura_;
- aura::Window* content_window_;
-
// We can optionally have a parent which can order us to close, or own
// children who we're responsible for closing when we CloseNow().
DesktopWindowTreeHostX11* window_parent_;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index 94d8a5768b1..73507805813 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -8,7 +8,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
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 1e17f0f4cf4..e0a11a00d46 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -11,7 +11,6 @@
#include <vector>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index a9be3abbd01..76f19a26a0b 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -147,7 +146,6 @@ void NativeWidgetAura::SetShadowElevationFromInitParams(
// NativeWidgetAura, internal::NativeWidgetPrivate implementation:
void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
- // Aura needs to know which desktop (Ash or regular) will manage this widget.
// See Widget::InitParams::context for details.
DCHECK(params.parent || params.context);
@@ -520,8 +518,8 @@ void NativeWidgetAura::Close() {
if (!close_widget_factory_.HasWeakPtrs()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&NativeWidgetAura::CloseNow,
- close_widget_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&NativeWidgetAura::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
}
}
diff --git a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
index 28bfeac0fef..b4de50c7e2b 100644
--- a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
@@ -4,7 +4,6 @@
#include "ui/views/widget/native_widget_aura.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/window.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/native_widget_factory.h"
diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h
index 8f2e56a4a4d..018bc2ce9d3 100644
--- a/chromium/ui/views/widget/native_widget_delegate.h
+++ b/chromium/ui/views/widget/native_widget_delegate.h
@@ -56,7 +56,8 @@ class VIEWS_EXPORT NativeWidgetDelegate {
virtual bool IsAlwaysRenderAsActive() const = 0;
// Called when the activation state of a window has changed.
- virtual void OnNativeWidgetActivationChanged(bool active) = 0;
+ // Returns true if this event should be handled.
+ virtual bool OnNativeWidgetActivationChanged(bool active) = 0;
// Called when native focus moves from one native view to another.
virtual void OnNativeFocus() = 0;
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index f5db821551e..223eb1191d1 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -8,6 +8,7 @@
#include <utility>
+#include "base/command_line.h"
#import "base/mac/bind_objc_block.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
@@ -16,6 +17,7 @@
#include "components/crash/core/common/crash_key.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
#import "ui/base/cocoa/window_size_constants.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/gfx/font_list.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/gfx/mac/nswindow_frame_controls.h"
@@ -46,6 +48,11 @@
namespace views {
namespace {
+bool AreModalAnimationsEnabled() {
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableModalAnimations);
+}
+
NSInteger StyleMaskForParams(const Widget::InitParams& params) {
// If the Widget is modal, it will be displayed as a sheet. This works best if
// it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the
@@ -332,11 +339,8 @@ void NativeWidgetMac::SetSize(const gfx::Size& size) {
}
void NativeWidgetMac::StackAbove(gfx::NativeView native_view) {
- // NativeWidgetMac currently only has machinery for stacking windows, and only
- // stacks child windows above parents. That's currently all this is used for.
- // DCHECK if a new use case comes along.
- DCHECK(bridge_ && bridge_->parent());
- DCHECK_EQ([native_view window], bridge_->parent()->GetNSWindow());
+ NSInteger view_parent = native_view.window.windowNumber;
+ [GetNativeWindow() orderWindow:NSWindowAbove relativeTo:view_parent];
}
void NativeWidgetMac::StackAtTop() {
@@ -365,7 +369,8 @@ void NativeWidgetMac::Close() {
}
// For other modal types, animate the close.
- if (bridge_->animate() && delegate_->IsModal()) {
+ if (bridge_->animate() && AreModalAnimationsEnabled() &&
+ delegate_->IsModal()) {
[ViewsNSWindowCloseAnimator closeWindowWithAnimation:window];
return;
}
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
index 5d0dddf78c7..d07c9ba57f4 100644
--- a/chromium/ui/views/widget/root_view.cc
+++ b/chromium/ui/views/widget/root_view.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
@@ -73,7 +74,8 @@ class PreEventDispatchHandler : public ui::EventHandler {
View* v = NULL;
if (owner_->GetFocusManager()) // Can be NULL in unittests.
v = owner_->GetFocusManager()->GetFocusedView();
-
+// macOS doesn't have keyboard-triggered context menus.
+#if !defined(OS_MACOSX)
// Special case to handle keyboard-triggered context menus.
if (v && v->enabled() && ((event->key_code() == ui::VKEY_APPS) ||
(event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) {
@@ -88,6 +90,7 @@ class PreEventDispatchHandler : public ui::EventHandler {
v->ShowContextMenu(location, ui::MENU_SOURCE_KEYBOARD);
event->StopPropagation();
}
+#endif
}
View* owner_;
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index 9f0cd55a02f..82959179009 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "build/build_config.h"
#include "ui/events/event_utils.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/test/views_test_base.h"
@@ -111,6 +112,10 @@ class TestContextMenuController : public ContextMenuController {
// Tests that context menus are shown for certain key events (Shift+F10
// and VKEY_APPS) by the pre-target handler installed on RootView.
TEST_F(RootViewTest, ContextMenuFromKeyEvent) {
+#if defined(OS_MACOSX)
+ // This behavior is intentionally unsupported on macOS.
+ return;
+#endif
Widget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 926519dfa33..7bc25d68ab4 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -84,6 +84,9 @@ void NotifyCaretBoundsChanged(ui::InputMethod* input_method) {
} // namespace
+// static
+bool Widget::g_disable_activation_change_handling_ = false;
+
// A default implementation of WidgetDelegate, used by Widget when no
// WidgetDelegate is supplied.
class DefaultWidgetDelegate : public WidgetDelegate {
@@ -325,6 +328,9 @@ void Widget::Init(const InitParams& in_params) {
params.delegate : new DefaultWidgetDelegate(this);
widget_delegate_->set_can_activate(can_activate);
+ // Henceforth, ensure the delegate outlives the Widget.
+ widget_delegate_->can_delete_this_ = false;
+
ownership_ = params.ownership;
native_widget_ = CreateNativeWidget(params, this)->AsNativeWidgetPrivate();
root_view_.reset(CreateRootView());
@@ -1030,7 +1036,10 @@ bool Widget::IsAlwaysRenderAsActive() const {
return always_render_as_active_;
}
-void Widget::OnNativeWidgetActivationChanged(bool active) {
+bool Widget::OnNativeWidgetActivationChanged(bool active) {
+ if (g_disable_activation_change_handling_)
+ return false;
+
// On windows we may end up here before we've completed initialization (from
// an WM_NCACTIVATE). If that happens the WidgetDelegate likely doesn't know
// the Widget and will crash attempting to access it.
@@ -1042,6 +1051,8 @@ void Widget::OnNativeWidgetActivationChanged(bool active) {
if (non_client_view())
non_client_view()->frame_view()->ActivationChanged(active);
+
+ return true;
}
void Widget::OnNativeFocus() {
@@ -1092,6 +1103,7 @@ void Widget::OnNativeWidgetDestroying() {
void Widget::OnNativeWidgetDestroyed() {
for (WidgetObserver& observer : observers_)
observer.OnWidgetDestroyed(this);
+ widget_delegate_->can_delete_this_ = true;
widget_delegate_->DeleteDelegate();
widget_delegate_ = NULL;
native_widget_destroyed_ = true;
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 6c0c60807a2..e2df1f67a8b 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -276,8 +276,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// hierarchy this widget should be placed. (This is separate from |parent|;
// if you pass a RootWindow to |parent|, your window will be parented to
// |parent|. If you pass a RootWindow to |context|, we ask that RootWindow
- // where it wants your window placed.) NULL is not allowed if you are using
- // aura.
+ // where it wants your window placed.) Nullptr is not allowed on Windows and
+ // Linux. Nullptr is allowed on Chrome OS, which will place the window on
+ // the default desktop for new windows.
gfx::NativeWindow context;
// If true, forces the window to be shown in the taskbar, even for window
// types that do not appear in the taskbar by default (popup and bubble).
@@ -789,7 +790,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
bool CanActivate() const override;
bool IsAlwaysRenderAsActive() const override;
void SetAlwaysRenderAsActive(bool always_render_as_active) override;
- void OnNativeWidgetActivationChanged(bool active) override;
+ bool OnNativeWidgetActivationChanged(bool active) override;
void OnNativeFocus() override;
void OnNativeBlur() override;
void OnNativeWidgetVisibilityChanging(bool visible) override;
@@ -858,6 +859,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
friend class ButtonTest;
friend class TextfieldTest;
friend class ViewAuraTest;
+ friend void DisableActivationChangeHandlingForTests();
// Persists the window's restored position and "show" state using the
// window delegate.
@@ -883,6 +885,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// layer.
const View::Views& GetViewsWithLayers();
+ static bool g_disable_activation_change_handling_;
+
internal::NativeWidgetPrivate* native_widget_;
base::ObserverList<WidgetObserver> observers_;
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index 294113b8996..ea1c78ff1d6 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -4,6 +4,7 @@
#include "ui/views/widget/widget_delegate.h"
+#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
#include "ui/gfx/image/image_skia.h"
@@ -17,9 +18,9 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// WidgetDelegate:
-WidgetDelegate::WidgetDelegate()
- : default_contents_view_(NULL),
- can_activate_(true) {
+WidgetDelegate::WidgetDelegate() = default;
+WidgetDelegate::~WidgetDelegate() {
+ CHECK(can_delete_this_) << "A WidgetDelegate must outlive its Widget";
}
void WidgetDelegate::OnWidgetMove() {
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 8ae82197483..c1cfaebc417 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -184,12 +184,16 @@ class VIEWS_EXPORT WidgetDelegate {
virtual void GetAccessiblePanes(std::vector<View*>* panes) {}
protected:
- virtual ~WidgetDelegate() {}
+ virtual ~WidgetDelegate();
private:
- View* default_contents_view_;
+ friend class Widget;
- bool can_activate_;
+ View* default_contents_view_ = nullptr;
+ bool can_activate_ = true;
+
+ // Managed by Widget. Ensures |this| outlives its Widget.
+ bool can_delete_this_ = true;
DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
};
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 1cad461f7dd..db44bd41b88 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -377,9 +377,7 @@ class TouchEventHandler : public ui::EventHandler {
}
void WaitForEvents() {
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
- base::RunLoop run_loop;
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
@@ -543,11 +541,12 @@ TEST_F(WidgetTestInteractive, DisableCaptureWidgetFromMousePress) {
gfx::Point location(20, 20);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&Widget::OnMouseEvent, base::Unretained(second),
- base::Owned(new ui::MouseEvent(
- ui::ET_MOUSE_RELEASED, location, location,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON))));
+ FROM_HERE,
+ base::BindOnce(
+ &Widget::OnMouseEvent, base::Unretained(second),
+ base::Owned(new ui::MouseEvent(
+ ui::ET_MOUSE_RELEASED, location, location, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON))));
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
@@ -845,8 +844,9 @@ class WidgetActivationTest : public Widget {
~WidgetActivationTest() override {}
- void OnNativeWidgetActivationChanged(bool active) override {
+ bool OnNativeWidgetActivationChanged(bool active) override {
active_ = active;
+ return true;
}
bool active() const { return active_; }
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index 76a9b283676..b978aabb83c 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -3226,13 +3226,7 @@ class FullscreenAwareFrame : public views::NonClientFrameView {
// Tests that frame Layout is called when a widget goes fullscreen without
// changing its size or title.
-// Fails on Mac, but only on bots. http://crbug.com/607403.
-#if defined(OS_MACOSX)
-#define MAYBE_FullscreenFrameLayout DISABLED_FullscreenFrameLayout
-#else
-#define MAYBE_FullscreenFrameLayout FullscreenFrameLayout
-#endif
-TEST_F(WidgetTest, MAYBE_FullscreenFrameLayout) {
+TEST_F(WidgetTest, FullscreenFrameLayout) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
FullscreenAwareFrame* frame = new FullscreenAwareFrame(widget.get());
widget->non_client_view()->SetFrameView(frame); // Owns |frame|.
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index c8fb7eecb9c..6a468941cf4 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -31,7 +31,6 @@
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/view_prop.h"
-#include "ui/base/win/direct_manipulation.h"
#include "ui/base/win/internal_constants.h"
#include "ui/base/win/lock_state.h"
#include "ui/base/win/mouse_wheel_util.h"
@@ -369,6 +368,8 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
left_button_down_on_caption_(false),
background_fullscreen_hack_(false),
pointer_events_for_touch_(features::IsUsingWMPointerForTouch()),
+ precision_touchpad_scroll_phase_enabled_(base::FeatureList::IsEnabled(
+ features::kPrecisionTouchpadScrollPhase)),
autohide_factory_(this),
weak_factory_(this) {}
@@ -411,13 +412,6 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
DCHECK(delegate_->GetHWNDMessageDelegateInputMethod());
delegate_->GetHWNDMessageDelegateInputMethod()->AddObserver(this);
- // Direct Manipulation is enabled on Windows 10+. The CreateInstance function
- // returns NULL if Direct Manipulation is not available.
- direct_manipulation_helper_ =
- ui::win::DirectManipulationHelper::CreateInstance();
- if (direct_manipulation_helper_)
- direct_manipulation_helper_->Initialize(hwnd());
-
// Disable pen flicks (http://crbug.com/506977)
base::win::DisableFlicks(hwnd());
}
@@ -456,8 +450,8 @@ void HWNDMessageHandler::Close() {
// dereference us when the callback returns).
waiting_for_close_now_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&HWNDMessageHandler::CloseNow, weak_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&HWNDMessageHandler::CloseNow,
+ weak_factory_.GetWeakPtr()));
}
}
@@ -601,8 +595,6 @@ void HWNDMessageHandler::Show() {
ShowWindowWithState(ui::SHOW_STATE_INACTIVE);
}
}
- if (direct_manipulation_helper_)
- direct_manipulation_helper_->Activate(hwnd());
}
void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
@@ -1068,6 +1060,119 @@ void HWNDMessageHandler::HandleParentChanged() {
touch_ids_.clear();
}
+void HWNDMessageHandler::ApplyPinchZoomScale(float scale) {
+ POINT cursor_pos = {0};
+ ::GetCursorPos(&cursor_pos);
+ ScreenToClient(hwnd(), &cursor_pos);
+
+ ui::GestureEventDetails event_details(ui::ET_GESTURE_PINCH_UPDATE);
+ event_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+ event_details.set_scale(scale);
+
+ ui::GestureEvent event(cursor_pos.x, cursor_pos.y, ui::EF_NONE,
+ base::TimeTicks::Now(), event_details);
+ delegate_->HandleGestureEvent(&event);
+}
+
+void HWNDMessageHandler::ApplyPinchZoomBegin() {
+ POINT cursor_pos = {0};
+ ::GetCursorPos(&cursor_pos);
+ ScreenToClient(hwnd(), &cursor_pos);
+
+ ui::GestureEventDetails event_details(ui::ET_GESTURE_PINCH_BEGIN);
+ event_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+
+ ui::GestureEvent event(cursor_pos.x, cursor_pos.y, ui::EF_NONE,
+ base::TimeTicks::Now(), event_details);
+ delegate_->HandleGestureEvent(&event);
+}
+
+void HWNDMessageHandler::ApplyPinchZoomEnd() {
+ POINT cursor_pos = {0};
+ ::GetCursorPos(&cursor_pos);
+ ScreenToClient(hwnd(), &cursor_pos);
+
+ ui::GestureEventDetails event_details(ui::ET_GESTURE_PINCH_END);
+ event_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+
+ ui::GestureEvent event(cursor_pos.x, cursor_pos.y, ui::EF_NONE,
+ base::TimeTicks::Now(), event_details);
+ delegate_->HandleGestureEvent(&event);
+}
+
+void HWNDMessageHandler::ApplyPanGestureEvent(
+ int scroll_x,
+ int scroll_y,
+ ui::EventMomentumPhase momentum_phase,
+ ui::ScrollEventPhase phase) {
+ gfx::Vector2d offset{scroll_x, scroll_y};
+
+ POINT root_location = {0};
+ ::GetCursorPos(&root_location);
+
+ POINT location = {root_location.x, root_location.y};
+ ScreenToClient(hwnd(), &location);
+
+ gfx::Point cursor_location(location);
+ gfx::Point cursor_root_location(root_location);
+
+ int modifiers = ui::GetModifiersFromKeyState();
+
+ if (precision_touchpad_scroll_phase_enabled_) {
+ ui::ScrollEvent event(ui::ET_SCROLL, cursor_location, ui::EventTimeForNow(),
+ modifiers, scroll_x, scroll_y, scroll_x, scroll_y, 2,
+ momentum_phase, phase);
+ delegate_->HandleScrollEvent(&event);
+ } else {
+ ui::MouseWheelEvent wheel_event(
+ offset, cursor_location, cursor_root_location, base::TimeTicks::Now(),
+ modifiers | ui::EF_PRECISION_SCROLLING_DELTA, ui::EF_NONE);
+ delegate_->HandleMouseEvent(&wheel_event);
+ }
+}
+
+void HWNDMessageHandler::ApplyPanGestureScroll(int scroll_x, int scroll_y) {
+ ApplyPanGestureEvent(scroll_x, scroll_y, ui::EventMomentumPhase::NONE,
+ ui::ScrollEventPhase::kUpdate);
+}
+
+void HWNDMessageHandler::ApplyPanGestureFling(int scroll_x, int scroll_y) {
+ ApplyPanGestureEvent(scroll_x, scroll_y,
+ ui::EventMomentumPhase::INERTIAL_UPDATE,
+ ui::ScrollEventPhase::kNone);
+}
+
+void HWNDMessageHandler::ApplyPanGestureScrollBegin(int scroll_x,
+ int scroll_y) {
+ // Phase information will be ingored in ApplyPanGestureEvent().
+ ApplyPanGestureEvent(scroll_x, scroll_y, ui::EventMomentumPhase::NONE,
+ ui::ScrollEventPhase::kBegan);
+}
+
+void HWNDMessageHandler::ApplyPanGestureScrollEnd() {
+ if (!precision_touchpad_scroll_phase_enabled_)
+ return;
+
+ ApplyPanGestureEvent(0, 0, ui::EventMomentumPhase::NONE,
+ ui::ScrollEventPhase::kEnd);
+}
+
+void HWNDMessageHandler::ApplyPanGestureFlingBegin() {
+ if (!precision_touchpad_scroll_phase_enabled_)
+ return;
+
+ ApplyPanGestureEvent(0, 0, ui::EventMomentumPhase::BEGAN,
+ ui::ScrollEventPhase::kNone);
+}
+
+void HWNDMessageHandler::ApplyPanGestureFlingEnd() {
+ if (!precision_touchpad_scroll_phase_enabled_)
+ return;
+
+ ApplyPanGestureEvent(0, 0, ui::EventMomentumPhase::END,
+ ui::ScrollEventPhase::kNone);
+}
+
////////////////////////////////////////////////////////////////////////////////
// HWNDMessageHandler, private:
@@ -1334,8 +1439,9 @@ void HWNDMessageHandler::ForceRedrawWindow(int attempts) {
if (--attempts <= 0)
return;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&HWNDMessageHandler::ForceRedrawWindow,
- weak_factory_.GetWeakPtr(), attempts),
+ FROM_HERE,
+ base::BindOnce(&HWNDMessageHandler::ForceRedrawWindow,
+ weak_factory_.GetWeakPtr(), attempts),
base::TimeDelta::FromMilliseconds(500));
return;
}
@@ -2127,7 +2233,7 @@ LRESULT HWNDMessageHandler::OnScrollMessage(UINT message,
MSG msg = {
hwnd(), message, w_param, l_param, static_cast<DWORD>(GetMessageTime())};
ui::ScrollEvent event(msg);
- delegate_->HandleScrollEvent(event);
+ delegate_->HandleScrollEvent(&event);
return 0;
}
@@ -2347,8 +2453,9 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
event_time, &touch_events);
touch_down_contexts_++;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&HWNDMessageHandler::ResetTouchDownContext,
- weak_factory_.GetWeakPtr()),
+ FROM_HERE,
+ base::BindOnce(&HWNDMessageHandler::ResetTouchDownContext,
+ weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kTouchDownContextResetTimeout));
} else {
if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
@@ -2381,8 +2488,8 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
// events on windows don't fire if we enter a modal loop in the context of
// a touch event.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&HWNDMessageHandler::HandleTouchEvents,
- weak_factory_.GetWeakPtr(), touch_events));
+ FROM_HERE, base::BindOnce(&HWNDMessageHandler::HandleTouchEvents,
+ weak_factory_.GetWeakPtr(), touch_events));
}
CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param));
SetMsgHandled(FALSE);
@@ -2487,8 +2594,9 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
// and send us further updates.
ignore_window_pos_changes_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&HWNDMessageHandler::StopIgnoringPosChanges,
- weak_factory_.GetWeakPtr()));
+ FROM_HERE,
+ base::BindOnce(&HWNDMessageHandler::StopIgnoringPosChanges,
+ weak_factory_.GetWeakPtr()));
}
last_monitor_ = monitor;
last_monitor_rect_ = monitor_rect;
@@ -2540,13 +2648,9 @@ void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) {
SetDwmFrameExtension(DwmFrameState::ON);
if (window_pos->flags & SWP_SHOWWINDOW) {
delegate_->HandleVisibilityChanged(true);
- if (direct_manipulation_helper_)
- direct_manipulation_helper_->Activate(hwnd());
SetDwmFrameExtension(DwmFrameState::ON);
} else if (window_pos->flags & SWP_HIDEWINDOW) {
delegate_->HandleVisibilityChanged(false);
- if (direct_manipulation_helper_)
- direct_manipulation_helper_->Deactivate(hwnd());
}
SetMsgHandled(FALSE);
@@ -2575,8 +2679,10 @@ void HWNDMessageHandler::OnSessionChange(WPARAM status_code) {
void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) {
base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
- for (size_t i = 0; i < touch_events.size() && ref; ++i)
- delegate_->HandleTouchEvent(touch_events[i]);
+ for (size_t i = 0; i < touch_events.size() && ref; ++i) {
+ ui::TouchEvent* touch_event = const_cast<ui::TouchEvent*>(&touch_events[i]);
+ delegate_->HandleTouchEvent(touch_event);
+ }
}
void HWNDMessageHandler::ResetTouchDownContext() {
@@ -2686,25 +2792,22 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message,
// OnMouseEvent.
active_mouse_tracking_flags_ = 0;
} else if (event.type() == ui::ET_MOUSEWHEEL) {
+ ui::MouseWheelEvent mouse_wheel_event(msg);
// Reroute the mouse wheel to the window under the pointer if applicable.
return (ui::RerouteMouseWheel(hwnd(), w_param, l_param) ||
- delegate_->HandleMouseEvent(ui::MouseWheelEvent(msg))) ? 0 : 1;
+ delegate_->HandleMouseEvent(&mouse_wheel_event))
+ ? 0
+ : 1;
}
// There are cases where the code handling the message destroys the window,
// so use the weak ptr to check if destruction occured or not.
base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
- bool handled = delegate_->HandleMouseEvent(event);
+ bool handled = delegate_->HandleMouseEvent(&event);
if (!ref.get())
return 0;
- if (direct_manipulation_helper_ && track_mouse &&
- (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL)) {
- direct_manipulation_helper_->HandleMouseWheel(hwnd(), message, w_param,
- l_param);
- }
-
if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU &&
w_param != HTCAPTION &&
delegate_->GetFrameMode() == FrameMode::CUSTOM_DRAWN) {
@@ -2799,7 +2902,7 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message,
// There are cases where the code handling the message destroys the
// window, so use the weak ptr to check if destruction occurred or not.
base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
- delegate_->HandleTouchEvent(event);
+ delegate_->HandleTouchEvent(&event);
if (event_type == ui::ET_TOUCH_RELEASED)
id_generator_.ReleaseNumber(pointer_id);
@@ -2835,9 +2938,9 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypePen(UINT message,
base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
if (event) {
if (event->IsTouchEvent()) {
- delegate_->HandleTouchEvent(*event->AsTouchEvent());
+ delegate_->HandleTouchEvent(event->AsTouchEvent());
} else if (event->IsMouseEvent()) {
- delegate_->HandleMouseEvent(*event->AsMouseEvent());
+ delegate_->HandleMouseEvent(event->AsMouseEvent());
} else {
NOTREACHED();
}
@@ -3031,9 +3134,6 @@ void HWNDMessageHandler::SetBoundsInternal(const gfx::Rect& bounds_in_pixels,
delegate_->HandleClientSizeChanged(GetClientAreaBounds().size());
ResetWindowRegion(false, true);
}
-
- if (direct_manipulation_helper_)
- direct_manipulation_helper_->SetBounds(bounds_in_pixels);
}
void HWNDMessageHandler::CheckAndHandleBackgroundFullscreenOnMonitor(
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 5d5765c1928..11c76b89e38 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -41,9 +41,6 @@ class AXSystemCaretWin;
class InputMethod;
class TextInputClient;
class ViewProp;
-namespace win {
-class DirectManipulationHelper;
-} // namespace win
} // namespace ui
namespace views {
@@ -261,13 +258,25 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
WPARAM w_param,
LPARAM l_param,
bool* handled) override;
-
LRESULT HandleNcHitTestMessage(unsigned int message,
WPARAM w_param,
LPARAM l_param,
bool* handled) override;
-
void HandleParentChanged() override;
+ void ApplyPinchZoomScale(float scale) override;
+ void ApplyPinchZoomBegin() override;
+ void ApplyPinchZoomEnd() override;
+ void ApplyPanGestureScroll(int scroll_x, int scroll_y) override;
+ void ApplyPanGestureFling(int scroll_x, int scroll_y) override;
+ void ApplyPanGestureScrollBegin(int scroll_x, int scroll_y) override;
+ void ApplyPanGestureScrollEnd() override;
+ void ApplyPanGestureFlingBegin() override;
+ void ApplyPanGestureFlingEnd() override;
+
+ void ApplyPanGestureEvent(int scroll_x,
+ int scroll_y,
+ ui::EventMomentumPhase momentum_phase,
+ ui::ScrollEventPhase phase);
// Returns the auto-hide edges of the appbar. See
// ViewsDelegate::GetAppbarAutohideEdges() for details. If the edges change,
@@ -728,12 +737,6 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// Some assistive software need to track the location of the caret.
std::unique_ptr<ui::AXSystemCaretWin> ax_system_caret_;
- // This class provides functionality to register the legacy window as a
- // Direct Manipulation consumer. This allows us to support smooth scroll
- // in Chrome on Windows 10.
- std::unique_ptr<ui::win::DirectManipulationHelper>
- direct_manipulation_helper_;
-
// The location where the user clicked on the caption. We cache this when we
// receive the WM_NCLBUTTONDOWN message. We use this in the subsequent
// WM_NCMOUSEMOVE message to see if the mouse actually moved.
@@ -757,6 +760,10 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// not WM_TOUCH events.
bool pointer_events_for_touch_;
+ // True if we enable feature kPrecisionTouchpadScrollPhase. Indicate we will
+ // report the scroll phase information or not.
+ bool precision_touchpad_scroll_phase_enabled_;
+
// This is a map of the HMONITOR to full screeen window instance. It is safe
// to keep a raw pointer to the HWNDMessageHandler instance as we track the
// window destruction and ensure that the map is cleaned up.
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index d13f807e4a7..1b2d98a8573 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -186,7 +186,7 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Called when a mouse event is received. Returns true if the event was
// handled by the delegate.
- virtual bool HandleMouseEvent(const ui::MouseEvent& event) = 0;
+ virtual bool HandleMouseEvent(ui::MouseEvent* event) = 0;
// Called when a pointer event is received. Returns true if the event was
// handled by the delegate.
@@ -197,7 +197,7 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
virtual void HandleKeyEvent(ui::KeyEvent* event) = 0;
// Called when a touch event is received.
- virtual void HandleTouchEvent(const ui::TouchEvent& event) = 0;
+ virtual void HandleTouchEvent(ui::TouchEvent* event) = 0;
// Called when an IME message needs to be processed by the delegate. Returns
// true if the event was handled and no default processing should be
@@ -241,7 +241,11 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Called when a scroll event is received. Returns true if the event was
// handled by the delegate.
- virtual bool HandleScrollEvent(const ui::ScrollEvent& event) = 0;
+ virtual bool HandleScrollEvent(ui::ScrollEvent* event) = 0;
+
+ // Called when a gesture event is received. Returns true if the event was
+ // handled by the delegate.
+ virtual bool HandleGestureEvent(ui::GestureEvent* event) = 0;
// Called when the window size is about to change.
virtual void HandleWindowSizeChanging() = 0;
diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc
index 17f51705029..5de8173f343 100644
--- a/chromium/ui/views/win/pen_event_processor.cc
+++ b/chromium/ui/views/win/pen_event_processor.cc
@@ -4,7 +4,6 @@
#include "pen_event_processor.h"
-#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "ui/events/event_utils.h"
diff --git a/chromium/ui/views/word_lookup_client.h b/chromium/ui/views/word_lookup_client.h
index d9c200f5566..15b9c795df6 100644
--- a/chromium/ui/views/word_lookup_client.h
+++ b/chromium/ui/views/word_lookup_client.h
@@ -22,9 +22,13 @@ class VIEWS_EXPORT WordLookupClient {
// displayed at the point, returns a nearby word. |baseline_point| should
// correspond to the baseline point of the leftmost glyph of the |word| in the
// view's coordinates. Returns false, if no word can be retrieved.
- virtual bool GetDecoratedWordAtPoint(const gfx::Point& point,
- gfx::DecoratedText* decorated_word,
- gfx::Point* baseline_point) = 0;
+ virtual bool GetWordLookupDataAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) = 0;
+
+ virtual bool GetWordLookupDataFromSelection(
+ gfx::DecoratedText* decorated_text,
+ gfx::Point* baseline_point) = 0;
protected:
virtual ~WordLookupClient() {}
diff --git a/chromium/ui/web_dialogs/BUILD.gn b/chromium/ui/web_dialogs/BUILD.gn
index 63923b1f1ed..54a3320caef 100644
--- a/chromium/ui/web_dialogs/BUILD.gn
+++ b/chromium/ui/web_dialogs/BUILD.gn
@@ -24,11 +24,12 @@ jumbo_component("web_dialogs") {
"//content/public/common",
"//skia",
"//ui/base",
+ "//ui/webui",
"//url",
]
if (!is_ios) {
- deps += [ "//third_party/WebKit/public:blink_headers" ]
+ deps += [ "//third_party/blink/public:blink_headers" ]
}
}
diff --git a/chromium/ui/web_dialogs/DEPS b/chromium/ui/web_dialogs/DEPS
index d988b2ff7e0..6bcf66b60ac 100644
--- a/chromium/ui/web_dialogs/DEPS
+++ b/chromium/ui/web_dialogs/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+content/public",
- "+third_party/WebKit/public/platform/WebGestureEvent.h",
+ "+third_party/blink/public/platform/web_gesture_event.h",
"+ui/base",
"+ui/gfx",
+ "+ui/webui",
]
diff --git a/chromium/ui/web_dialogs/web_dialog_ui.cc b/chromium/ui/web_dialogs/web_dialog_ui.cc
index 5b72e0c04f9..9b1d765ce2d 100644
--- a/chromium/ui/web_dialogs/web_dialog_ui.cc
+++ b/chromium/ui/web_dialogs/web_dialog_ui.cc
@@ -39,37 +39,31 @@ class WebDialogDelegateUserData : public base::SupportsUserData::Data {
} // namespace
-WebDialogUI::WebDialogUI(content::WebUI* web_ui)
- : WebUIController(web_ui) {
-}
-
-WebDialogUI::~WebDialogUI() {
- // Don't unregister our user data. During the teardown of the WebContents,
- // this will be deleted, but the WebContents will already be destroyed.
- //
- // This object is owned indirectly by the WebContents. WebUIs can change, so
- // it's scary if this WebUI is changed out and replaced with something else,
- // since the user data will still point to the old delegate. But the delegate
- // is itself the owner of the WebContents for a dialog so will be in scope,
- // and the HTML dialogs won't swap WebUIs anyway since they don't navigate.
-}
-
-void WebDialogUI::CloseDialog(const base::ListValue* args) {
- OnDialogClosed(args);
-}
-
// static
-void WebDialogUI::SetDelegate(content::WebContents* web_contents,
- WebDialogDelegate* delegate) {
+void WebDialogUIBase::SetDelegate(content::WebContents* web_contents,
+ WebDialogDelegate* delegate) {
web_contents->SetUserData(
&kWebDialogDelegateUserDataKey,
std::make_unique<WebDialogDelegateUserData>(delegate));
}
-////////////////////////////////////////////////////////////////////////////////
-// Private:
+WebDialogUIBase::WebDialogUIBase(content::WebUI* web_ui) : web_ui_(web_ui) {}
+
+// Don't unregister our user data. During the teardown of the WebContents, this
+// will be deleted, but the WebContents will already be destroyed.
+//
+// This object is owned indirectly by the WebContents. WebUIs can change, so
+// it's scary if this WebUI is changed out and replaced with something else,
+// since the user data will still point to the old delegate. But the delegate is
+// itself the owner of the WebContents for a dialog so will be in scope, and the
+// HTML dialogs won't swap WebUIs anyway since they don't navigate.
+WebDialogUIBase::~WebDialogUIBase() = default;
+
+void WebDialogUIBase::CloseDialog(const base::ListValue* args) {
+ OnDialogClosed(args);
+}
-WebDialogDelegate* WebDialogUI::GetDelegate(
+WebDialogDelegate* WebDialogUIBase::GetDelegate(
content::WebContents* web_contents) {
WebDialogDelegateUserData* user_data =
static_cast<WebDialogDelegateUserData*>(
@@ -78,17 +72,18 @@ WebDialogDelegate* WebDialogUI::GetDelegate(
return user_data ? user_data->delegate() : NULL;
}
-
-void WebDialogUI::RenderFrameCreated(RenderFrameHost* render_frame_host) {
+void WebDialogUIBase::HandleRenderFrameCreated(
+ RenderFrameHost* render_frame_host) {
// Hook up the javascript function calls, also known as chrome.send("foo")
// calls in the HTML, to the actual C++ functions.
- web_ui()->RegisterMessageCallback("dialogClose",
- base::Bind(&WebDialogUI::OnDialogClosed, base::Unretained(this)));
+ web_ui_->RegisterMessageCallback(
+ "dialogClose", base::BindRepeating(&WebDialogUIBase::OnDialogClosed,
+ base::Unretained(this)));
// Pass the arguments to the renderer supplied by the delegate.
std::string dialog_args;
std::vector<WebUIMessageHandler*> handlers;
- WebDialogDelegate* delegate = GetDelegate(web_ui()->GetWebContents());
+ WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
if (delegate) {
dialog_args = delegate->GetDialogArgs();
delegate->GetWebUIMessageHandlers(&handlers);
@@ -96,17 +91,17 @@ void WebDialogUI::RenderFrameCreated(RenderFrameHost* render_frame_host) {
content::RenderViewHost* render_view_host =
render_frame_host->GetRenderViewHost();
- if (0 != (web_ui()->GetBindings() & content::BINDINGS_POLICY_WEB_UI))
+ if (0 != (web_ui_->GetBindings() & content::BINDINGS_POLICY_WEB_UI))
render_view_host->SetWebUIProperty("dialogArguments", dialog_args);
for (WebUIMessageHandler* handler : handlers)
- web_ui()->AddMessageHandler(base::WrapUnique(handler));
+ web_ui_->AddMessageHandler(base::WrapUnique(handler));
if (delegate)
- delegate->OnDialogShown(web_ui(), render_view_host);
+ delegate->OnDialogShown(web_ui_, render_view_host);
}
-void WebDialogUI::OnDialogClosed(const base::ListValue* args) {
- WebDialogDelegate* delegate = GetDelegate(web_ui()->GetWebContents());
+void WebDialogUIBase::OnDialogClosed(const base::ListValue* args) {
+ WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
if (delegate) {
std::string json_retval;
if (args && !args->empty() && !args->GetString(0, &json_retval))
@@ -116,4 +111,13 @@ void WebDialogUI::OnDialogClosed(const base::ListValue* args) {
}
}
+WebDialogUI::WebDialogUI(content::WebUI* web_ui)
+ : WebDialogUIBase(web_ui), content::WebUIController(web_ui) {}
+
+WebDialogUI::~WebDialogUI() = default;
+
+void WebDialogUI::RenderFrameCreated(RenderFrameHost* render_frame_host) {
+ HandleRenderFrameCreated(render_frame_host);
+}
+
} // namespace ui
diff --git a/chromium/ui/web_dialogs/web_dialog_ui.h b/chromium/ui/web_dialogs/web_dialog_ui.h
index 001de1956e7..8c1c726a2be 100644
--- a/chromium/ui/web_dialogs/web_dialog_ui.h
+++ b/chromium/ui/web_dialogs/web_dialog_ui.h
@@ -15,6 +15,7 @@
#include "content/public/browser/web_ui_controller.h"
#include "ui/base/ui_base_types.h"
#include "ui/web_dialogs/web_dialogs_export.h"
+#include "ui/webui/mojo_web_ui_controller.h"
#include "url/gurl.h"
namespace content {
@@ -25,6 +26,35 @@ namespace ui {
class WebDialogDelegate;
+class WEB_DIALOGS_EXPORT WebDialogUIBase {
+ public:
+ // Sets the delegate on the WebContents.
+ static void SetDelegate(content::WebContents* web_contents,
+ WebDialogDelegate* delegate);
+
+ WebDialogUIBase(content::WebUI* web_ui);
+
+ // Close the dialog, passing the specified arguments to the close handler.
+ void CloseDialog(const base::ListValue* args);
+
+ protected:
+ virtual ~WebDialogUIBase();
+
+ // Prepares |render_frame_host| to host a dialog.
+ void HandleRenderFrameCreated(content::RenderFrameHost* render_frame_host);
+
+ private:
+ // Gets the delegate for the WebContent set with SetDelegate.
+ static WebDialogDelegate* GetDelegate(content::WebContents* web_contents);
+
+ // JS message handler.
+ void OnDialogClosed(const base::ListValue* args);
+
+ content::WebUI* web_ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDialogUIBase);
+};
+
// Displays file URL contents inside a modal web dialog.
//
// This application really should not use WebContents + WebUI. It should instead
@@ -36,42 +66,43 @@ class WebDialogDelegate;
// the dialog to pass its delegate to the Web UI without having nasty accessors
// on the WebContents. The correct design using RVH directly would avoid all of
// this.
-class WEB_DIALOGS_EXPORT WebDialogUI : public content::WebUIController {
+class WEB_DIALOGS_EXPORT WebDialogUI : public WebDialogUIBase,
+ public content::WebUIController {
public:
- struct WebDialogParams {
- // The URL for the content that will be loaded in the dialog.
- GURL url;
- // Width of the dialog.
- int width;
- // Height of the dialog.
- int height;
- // The JSON input to pass to the dialog when showing it.
- std::string json_input;
- };
-
// When created, the delegate should already be set as user data on the
// WebContents.
explicit WebDialogUI(content::WebUI* web_ui);
~WebDialogUI() override;
- // Close the dialog, passing the specified arguments to the close handler.
- void CloseDialog(const base::ListValue* args);
-
- // Sets the delegate on the WebContents.
- static void SetDelegate(content::WebContents* web_contents,
- WebDialogDelegate* delegate);
-
private:
- // WebUIController
+ // content::WebUIController:
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
- // Gets the delegate for the WebContent set with SetDelegate.
- static WebDialogDelegate* GetDelegate(content::WebContents* web_contents);
+ DISALLOW_COPY_AND_ASSIGN(WebDialogUI);
+};
- // JS message handler.
- void OnDialogClosed(const base::ListValue* args);
+// Displays file URL contents inside a modal web dialog while also enabling
+// Mojo calls to be made from within the dialog.
+template <typename Interface>
+class WEB_DIALOGS_EXPORT MojoWebDialogUI
+ : public WebDialogUIBase,
+ public MojoWebUIController<Interface> {
+ public:
+ // When created, the delegate should already be set as user data on the
+ // WebContents.
+ explicit MojoWebDialogUI(content::WebUI* web_ui)
+ : WebDialogUIBase(web_ui), MojoWebUIController<Interface>(web_ui) {}
+ ~MojoWebDialogUI() override {}
- DISALLOW_COPY_AND_ASSIGN(WebDialogUI);
+ private:
+ // content::WebUIController:
+ void RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) override {
+ MojoWebUIControllerBase::RenderFrameCreated(render_frame_host);
+ HandleRenderFrameCreated(render_frame_host);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MojoWebDialogUI);
};
} // namespace ui
diff --git a/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc b/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc
index 59f1658492f..758974b6279 100644
--- a/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc
+++ b/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "content/public/browser/web_contents.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
+#include "third_party/blink/public/platform/web_gesture_event.h"
using content::BrowserContext;
using content::OpenURLParams;
diff --git a/chromium/ui/webui/BUILD.gn b/chromium/ui/webui/BUILD.gn
new file mode 100644
index 00000000000..7757ffde500
--- /dev/null
+++ b/chromium/ui/webui/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+static_library("webui") {
+ sources = [
+ "mojo_web_ui_controller.cc",
+ "mojo_web_ui_controller.h",
+ ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//mojo/common",
+ "//services/service_manager/public/cpp",
+ ]
+}
diff --git a/chromium/ui/webui/DEPS b/chromium/ui/webui/DEPS
index 69b82adcf09..27c4e74db70 100644
--- a/chromium/ui/webui/DEPS
+++ b/chromium/ui/webui/DEPS
@@ -1,5 +1,8 @@
include_rules = [
+ "+content/public",
+ "+mojo/public/cpp/system/core.h",
"+net",
+ "+services/service_manager/public/cpp/binder_registry.h",
"+ui/base",
"+ui/gfx",
]
diff --git a/chromium/ui/webui/PLATFORM_OWNERS b/chromium/ui/webui/PLATFORM_OWNERS
index a4e5de4c6f9..e685160dc50 100644
--- a/chromium/ui/webui/PLATFORM_OWNERS
+++ b/chromium/ui/webui/PLATFORM_OWNERS
@@ -5,5 +5,6 @@ dpapad@chromium.org
dschuyler@chromium.org
michaelpg@chromium.org
pam@chromium.org
+stevenjb@chromium.org
tommycli@chromium.org
xiyuan@chromium.org
diff --git a/chromium/ui/webui/mojo_web_ui_controller.cc b/chromium/ui/webui/mojo_web_ui_controller.cc
new file mode 100644
index 00000000000..9005100a47c
--- /dev/null
+++ b/chromium/ui/webui/mojo_web_ui_controller.cc
@@ -0,0 +1,21 @@
+// 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/webui/mojo_web_ui_controller.h"
+
+#include "content/public/common/bindings_policy.h"
+
+namespace ui {
+
+MojoWebUIControllerBase::MojoWebUIControllerBase(content::WebUI* contents)
+ : content::WebUIController(contents) {}
+
+MojoWebUIControllerBase::~MojoWebUIControllerBase() = default;
+
+void MojoWebUIControllerBase::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ render_frame_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI);
+}
+
+} // namespace ui
diff --git a/chromium/ui/webui/mojo_web_ui_controller.h b/chromium/ui/webui/mojo_web_ui_controller.h
new file mode 100644
index 00000000000..26f200f8b51
--- /dev/null
+++ b/chromium/ui/webui/mojo_web_ui_controller.h
@@ -0,0 +1,78 @@
+// 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_WEBUI_MOJO_WEB_UI_CONTROLLER_H_
+#define UI_WEBUI_MOJO_WEB_UI_CONTROLLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "mojo/public/cpp/system/core.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+
+namespace ui {
+
+class MojoWebUIControllerBase : public content::WebUIController {
+ public:
+ explicit MojoWebUIControllerBase(content::WebUI* contents);
+ ~MojoWebUIControllerBase() override;
+
+ // content::WebUIController overrides:
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MojoWebUIControllerBase);
+};
+
+// MojoWebUIController is intended for web ui pages that use mojo. It is
+// expected that subclasses will do two things:
+// . In the constructor invoke AddMojoResourcePath() to register the bindings
+// files, eg:
+// AddMojoResourcePath("chrome/browser/ui/webui/omnibox/omnibox.mojom",
+// IDR_OMNIBOX_MOJO_JS);
+// . Override BindUIHandler() to create and bind the implementation of the
+// bindings.
+template <typename Interface>
+class MojoWebUIController : public MojoWebUIControllerBase,
+ public content::WebContentsObserver {
+ public:
+ explicit MojoWebUIController(content::WebUI* contents)
+ : MojoWebUIControllerBase(contents),
+ content::WebContentsObserver(contents->GetWebContents()),
+ weak_factory_(this) {
+ registry_.AddInterface<Interface>(base::Bind(
+ &MojoWebUIController::BindUIHandler, base::Unretained(this)));
+ }
+ ~MojoWebUIController() override {}
+
+ // content::WebContentsObserver implementation.
+ void OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override {
+ // Right now, this is expected to be called only for main frames.
+ DCHECK(!render_frame_host->GetParent());
+ registry_.TryBindInterface(interface_name, interface_pipe);
+ }
+
+ protected:
+ // Invoked to create the specific bindings implementation.
+ virtual void BindUIHandler(mojo::InterfaceRequest<Interface> request) = 0;
+
+ private:
+ service_manager::BinderRegistry registry_;
+
+ base::WeakPtrFactory<MojoWebUIController> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoWebUIController);
+};
+
+} // namespace ui
+
+#endif // UI_WEBUI_MOJO_WEB_UI_CONTROLLER_H_
diff --git a/chromium/ui/webui/resources/BUILD.gn b/chromium/ui/webui/resources/BUILD.gn
new file mode 100644
index 00000000000..d7050d52ba8
--- /dev/null
+++ b/chromium/ui/webui/resources/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+group("closure_compile") {
+ deps = [
+ "cr_components:closure_compile",
+ "cr_elements:closure_compile",
+ "js:closure_compile",
+ ]
+}
diff --git a/chromium/ui/webui/resources/PRESUBMIT.py b/chromium/ui/webui/resources/PRESUBMIT.py
index 26bc5ec895e..04c5e4e2bf8 100644
--- a/chromium/ui/webui/resources/PRESUBMIT.py
+++ b/chromium/ui/webui/resources/PRESUBMIT.py
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import os
+
def PostUploadHook(cl, change, output_api):
return output_api.EnsureCQIncludeTrybotsAreAdded(
cl,
@@ -18,6 +20,30 @@ def CheckChangeOnUpload(input_api, output_api):
def CheckChangeOnCommit(input_api, output_api):
return _CommonChecks(input_api, output_api)
+# For every modified gyp file, warn if the corresponding GN file is not updated.
+def _CheckForGNUpdate(input_api, output_api):
+ gyp_folders = set()
+ for f in input_api.AffectedFiles():
+ local_path = f.LocalPath()
+ if local_path.endswith('compiled_resources2.gyp'):
+ gyp_folders.add(os.path.dirname(local_path))
+
+ for f in input_api.AffectedFiles():
+ local_path = f.LocalPath()
+ dir_name = os.path.dirname(local_path)
+ if local_path.endswith('BUILD.gn') and dir_name in gyp_folders:
+ gyp_folders.remove(dir_name)
+
+ if not gyp_folders:
+ return []
+
+ return [output_api.PresubmitPromptWarning("""
+You may have forgotten to update the BUILD.gn Closure Compilation for the
+following folders:
+""" + "\n".join(["- " + x for x in gyp_folders]) + """
+
+Ping calamity@ or check go/closure-compile-gn for more details.
+""")]
def _CheckForTranslations(input_api, output_api):
shared_keywords = ['i18n(']
@@ -60,6 +86,7 @@ translation from the place using the shared code. For an example: see
def _CommonChecks(input_api, output_api):
results = []
results += _CheckForTranslations(input_api, output_api)
+ results += _CheckForGNUpdate(input_api, output_api)
results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
check_js=True)
try:
diff --git a/chromium/ui/webui/resources/cr_components/BUILD.gn b/chromium/ui/webui/resources/cr_components/BUILD.gn
new file mode 100644
index 00000000000..f3d71a3a372
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+group("closure_compile") {
+ deps = [
+ "certificate_manager:closure_compile",
+ "chromeos:closure_compile",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/BUILD.gn b/chromium/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
new file mode 100644
index 00000000000..2c8a161a813
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
@@ -0,0 +1,128 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":ca_trust_edit_dialog",
+ ":certificate_delete_confirmation_dialog",
+ ":certificate_entry",
+ ":certificate_list",
+ ":certificate_manager",
+ ":certificate_manager_types",
+ ":certificate_password_decryption_dialog",
+ ":certificate_password_encryption_dialog",
+ ":certificate_subentry",
+ ":certificates_browser_proxy",
+ ":certificates_error_dialog",
+ ]
+}
+
+js_library("ca_trust_edit_dialog") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
+
+js_library("certificate_delete_confirmation_dialog") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
+
+js_library("certificate_entry") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("certificate_list") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificate_subentry",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("certificate_manager") {
+ deps = [
+ ":certificate_list",
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:web_ui_listener_behavior",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink",
+ ]
+}
+
+js_library("certificate_manager_types") {
+ deps = [
+ ":certificates_browser_proxy",
+ ]
+}
+
+js_library("certificate_password_decryption_dialog") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("certificate_password_encryption_dialog") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("certificate_subentry") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
+ "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("certificates_browser_proxy") {
+ deps = [
+ "//ui/webui/resources/js:cr",
+ ]
+}
+
+js_library("certificates_error_dialog") {
+ deps = [
+ ":certificate_manager_types",
+ ":certificates_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.html
index 16e035ec313..388faf5d32e 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/ca_trust_edit_dialog.html
@@ -23,7 +23,7 @@
}
</style>
- <dialog is="cr-dialog" id="dialog" close-text="[[i18n('close')]]">
+ <cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">
[[i18n('certificateManagerCaTrustEditDialogTitle')]]
</div>
@@ -51,7 +51,7 @@
[[i18n('ok')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="ca_trust_edit_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
index fbf253c3a5d..73d8209664f 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
@@ -9,7 +9,7 @@
<dom-module id="certificate-delete-confirmation-dialog">
<template>
<style include="certificate-shared"></style>
- <dialog is="cr-dialog" id="dialog" close-text="[[i18n('close')]]">
+ <cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">
[[getTitleText_(model, certificateType)]]
</div>
@@ -24,7 +24,7 @@
[[i18n('ok')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="certificate_delete_confirmation_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
index 850da130e7f..664a410da38 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
@@ -10,7 +10,7 @@
<dom-module id="certificate-password-decryption-dialog">
<template>
<style include="certificate-shared"></style>
- <dialog is="cr-dialog" id="dialog" close-text="[[i18n('close')]]">
+ <cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">
[[i18n('certificateManagerDecryptPasswordTitle')]]
</div>
@@ -28,7 +28,7 @@
[[i18n('ok')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="certificate_password_decryption_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
index f17b2825fef..a3ad6fd22d4 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
@@ -14,7 +14,7 @@
margin-bottom: 20px;
}
</style>
- <dialog is="cr-dialog" id="dialog" close-text="[[i18n('close')]]">
+ <cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">
[[i18n('certificateManagerEncryptPasswordTitle')]]
</div>
@@ -38,7 +38,7 @@
[[i18n('ok')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="certificate_password_encryption_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
index 423a18a8e50..96310bc8b8a 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html
@@ -32,31 +32,35 @@
[[i18n('certificateManagerUntrusted')]]
</div>
<div class="name">[[model.name]]</div>
- <button is="paper-icon-button-light" class="icon-more-vert" id="dots"
- title="[[i18n('moreActions')]]" on-tap="onDotsTap_"></button>
- <template is="cr-lazy-render" id="menu">
- <dialog is="cr-action-menu">
- <button slot="item" class="dropdown-item" id="view"
- on-tap="onViewTap_">
- [[i18n('certificateManagerView')]]
- </button>
- <button slot="item" class="dropdown-item" id="edit"
- hidden$="[[!canEdit_(certificateType, model)]]"
- on-tap="onEditTap_">
- [[i18n('edit')]]
- </button>
- <button slot="item" class="dropdown-item" id="export"
- hidden$="[[!canExport_(certificateType, model)]]"
- on-tap="onExportTap_">
- [[i18n('certificateManagerExport')]]
- </button>
- <button slot="item" class="dropdown-item" id="delete"
- hidden$="[[!canDelete_(model)]]"
- on-tap="onDeleteTap_">
- [[i18n('certificateManagerDelete')]]
- </button>
- </dialog>
- </template>
+ <paper-icon-button-light class="icon-more-vert">
+ <button id="dots" title="[[i18n('moreActions')]]" on-tap="onDotsTap_">
+ </button>
+ </paper-icon-button-light>
+ <cr-lazy-render id="menu">
+ <template>
+ <cr-action-menu>
+ <button slot="item" class="dropdown-item" id="view"
+ on-tap="onViewTap_">
+ [[i18n('certificateManagerView')]]
+ </button>
+ <button slot="item" class="dropdown-item" id="edit"
+ hidden$="[[!canEdit_(certificateType, model)]]"
+ on-tap="onEditTap_">
+ [[i18n('edit')]]
+ </button>
+ <button slot="item" class="dropdown-item" id="export"
+ hidden$="[[!canExport_(certificateType, model)]]"
+ on-tap="onExportTap_">
+ [[i18n('certificateManagerExport')]]
+ </button>
+ <button slot="item" class="dropdown-item" id="delete"
+ hidden$="[[!canDelete_(model)]]"
+ on-tap="onDeleteTap_">
+ [[i18n('certificateManagerDelete')]]
+ </button>
+ </cr-action-menu>
+ </template>
+ </cr-lazy-render>
<div>
</template>
<script src="certificate_subentry.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
index f2bc22e51fc..8467bd7c15f 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.js
@@ -139,7 +139,7 @@ Polymer({
/** @private */
closePopupMenu_: function() {
- this.$$('dialog[is=cr-action-menu]').close();
+ this.$$('cr-action-menu').close();
},
/** @private */
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
index 2c0bb746765..ae1d5c587a9 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
@@ -8,7 +8,7 @@
<dom-module id="certificates-error-dialog">
<template>
<style include="certificate-shared"></style>
- <dialog is="cr-dialog" id="dialog" close-text="[[i18n('close')]]">
+ <cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">[[model.title]]</div>
<div slot="body">
<div>[[model.description]]</div>
@@ -23,7 +23,7 @@
[[i18n('ok')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="certificates_error_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn
new file mode 100644
index 00000000000..45863c8c1cd
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn
@@ -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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+group("closure_compile") {
+ deps = [
+ ":chromeos_resources",
+ "network:closure_compile",
+ "quick_unlock:closure_compile",
+ ]
+}
+
+js_type_check("chromeos_resources") {
+ deps = [
+ ":bluetooth_dialog",
+ ]
+}
+
+js_library("bluetooth_dialog") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/iron-resizable-behavior:iron-resizable-behavior-extracted",
+ "//third_party/polymer/v1_0/components-chromium/paper-input:paper-input-extracted",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+ externs_list = [
+ "$externs_path/bluetooth.js",
+ "$externs_path/bluetooth_private.js",
+ ]
+ extra_sources = [
+ "$interfaces_path/bluetooth_interface.js",
+ "$interfaces_path/bluetooth_private_interface.js",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html
index a71d029f68a..e42cfe1e2b1 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html
@@ -12,8 +12,8 @@
<dom-module id="bluetooth-dialog">
<template>
<style include="cr-hidden-style iron-flex">
- dialog {
- @apply --bluetooth-dialog-style;
+ cr-dialog {
+ --cr-dialog-native: var(--bluetooth-dialog-style);
}
#pairing {
@@ -73,7 +73,7 @@
}
</style>
<!-- TODO(stevenjb/dschuyler): Find a solution to support i18n{} here -->
- <dialog is="cr-dialog" id="dialog" no-cancel="[[noCancel]]"
+ <cr-dialog id="dialog" no-cancel="[[noCancel]]"
close-text="[[i18n('close')]]" on-cancel="onDialogCanceled_"
on-closed="onDialogCanceled_">
<div slot="title">[[dialogTitle]]</div>
@@ -136,7 +136,7 @@
<paper-button on-tap="close">[[i18n('ok')]]</paper-button>
</template>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="bluetooth_dialog.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
index b545b3536a9..386e2dae7a5 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.js
@@ -422,9 +422,9 @@ Polymer({
(pairing == PairingEventType.DISPLAY_PASSKEY ||
pairing == PairingEventType.KEYS_ENTERED ||
pairing == PairingEventType.CONFIRM_PASSKEY)) {
- var passkeyString = String(this.pairingEvent_.passkey);
- if (index < passkeyString.length)
- digit = passkeyString[index];
+ var passkeyString =
+ String(this.pairingEvent_.passkey).padStart(this.digits_.length, '0');
+ digit = passkeyString[index];
}
return digit;
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
new file mode 100644
index 00000000000..b64b9364a6a
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
@@ -0,0 +1,117 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":network_apnlist",
+ ":network_choose_mobile",
+ ":network_config",
+ ":network_config_input",
+ ":network_config_select",
+ ":network_ip_config",
+ ":network_nameservers",
+ ":network_property_list",
+ ":network_proxy",
+ ":network_proxy_exclusions",
+ ":network_proxy_input",
+ ":network_siminfo",
+ ]
+}
+
+js_library("network_apnlist") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_choose_mobile") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
+
+js_library("network_config") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
+
+js_library("network_config_input") {
+ deps = [
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_config_select") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
+
+js_library("network_ip_config") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_nameservers") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_property_list") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_proxy") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_proxy_input") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
+
+js_library("network_proxy_exclusions") {
+}
+
+js_library("network_siminfo") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/paper-input:paper-input-extracted",
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink",
+ ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
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 c4e5034e13d..eb882f59f78 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
@@ -82,7 +82,7 @@ Polymer({
},
/** @const */
- DefaultAccessPointName: 'none',
+ DefaultAccessPointName: 'NONE',
/**
* Polymer networkProperties changed method.
@@ -202,7 +202,12 @@ Polymer({
* @private
*/
onOtherApnChange_: function(event) {
- this.set('otherApn_.' + event.detail.field, event.detail.value);
+ // TODO(benchan/stevenjb): Move this to shill or
+ // onc_translator_onc_to_shill.cc.
+ var value = (event.detail.field == 'AccessPointName') ?
+ event.detail.value.toUpperCase() :
+ event.detail.value;
+ this.set('otherApn_.' + event.detail.field, value);
// Don't send a change event for 'Other' until the 'Save' button is tapped.
},
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 32c5b74d9e7..a7f29f7e318 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
@@ -54,10 +54,10 @@
onc-prefix="VPN.Type" disabled="[[hasGuid_(guid)]]">
</network-config-select>
<template is="dom-if" if="[[!showVpn_.OpenVPN]]">
- <network-config-input label="[[i18n('OncVPN-Username')]]"
+ <network-config-input label="[[i18n('OncVPN-L2TP-Username')]]"
value="{{configProperties_.VPN.L2TP.Username}}">
</network-config-input>
- <network-config-input label="[[i18n('OncVPN-Password')]]"
+ <network-config-input label="[[i18n('OncVPN-L2TP-Password')]]"
value="{{configProperties_.VPN.L2TP.Password}}" password>
</network-config-input>
<network-config-input label="[[i18n('OncVPN-IPsec-Group')]]"
@@ -70,10 +70,10 @@
</template>
</template>
<template is="dom-if" if="[[showVpn_.OpenVPN]]">
- <network-config-input label="[[i18n('OncVPN-Username')]]"
+ <network-config-input label="[[i18n('OncVPN-OpenVPN-Username')]]"
value="{{configProperties_.VPN.OpenVPN.Username}}">
</network-config-input>
- <network-config-input label="[[i18n('OncVPN-Password')]]"
+ <network-config-input label="[[i18n('OncVPN-OpenVPN-Password')]]"
value="{{configProperties_.VPN.OpenVPN.Password}}" password>
</network-config-input>
<network-config-input label="[[i18n('OncVPN-OpenVPN-OTP')]]"
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html
index d23f9ec5c4b..2ed533dd539 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html
@@ -22,7 +22,7 @@
width: var(--network-control-margin);
}
- #iconDiv button {
+ #iconDiv paper-icon-button-light {
margin: 0;
}
</style>
@@ -36,11 +36,11 @@
</paper-input-container>
<div id="iconDiv">
<template is="dom-if" if="[[password]]">
- <button is="paper-icon-button-light"
- on-tap="onShowPasswordTap_"
- class$="[[getIconClass_(showPassword)]]"
- title="[[getShowPasswordTitle_(showPassword)]]">
- </button>
+ <paper-icon-button-light class$="[[getIconClass_(showPassword)]]">
+ <button on-tap="onShowPasswordTap_"
+ title="[[getShowPasswordTitle_(showPassword)]]">
+ </button>
+ </paper-icon-button-light>
</template>
</div>
</div>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
index 4260815ca7f..b7e07cc1c72 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
@@ -43,15 +43,12 @@ Polymer({
/**
* The currently visible IP Config property dictionary. The 'RoutingPrefix'
* property is a human-readable mask instead of a prefix length.
- * @private {?{
+ * @private {{
* ipv4: (!CrOnc.IPConfigUIProperties|undefined),
* ipv6: (!CrOnc.IPConfigUIProperties|undefined)
- * }}
+ * }|undefined}
*/
- ipConfig_: {
- type: Object,
- value: null,
- },
+ ipConfig_: Object,
/**
* Array of properties to pass to the property list.
@@ -107,7 +104,7 @@ Polymer({
}
this.ipConfig_ = {ipv4: ipv4, ipv6: ipv6};
} else {
- this.ipConfig_ = null;
+ this.ipConfig_ = undefined;
}
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html
index 534ce962de2..dab56078818 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html
@@ -29,36 +29,33 @@
filter="[[computeFilter_(prefix, propertyDict, editFieldTypes)]]">
<div class="property-box single-column two-line stretch">
<!-- Property label -->
- <div>[[getPropertyLabel_(item, prefix)]]</div>
+ <div class="layout horizontal center">
+ <div>[[getPropertyLabel_(item, prefix)]]</div>
+ <template is="dom-if" restamp
+ if="[[isEditTypeAny_(item, editFieldTypes)]]">
+ <cr-policy-network-indicator
+ property="[[getProperty_(item, propertyDict)]]">
+ </cr-policy-network-indicator>
+ </template>
+ </div>
<!-- Uneditable property value -->
- <div class="layout horizontal"
- hidden="[[isEditable_(item, '', propertyDict, editFieldTypes)]]">
+ <template is="dom-if" restamp
+ if="[[!isEditable_(item, propertyDict, editFieldTypes)]]">
<div class="secondary">
[[getPropertyValue_(item, prefix, propertyDict)]]
</div>
- <cr-policy-network-indicator
- property="[[getProperty_(item, propertyDict)]]">
- </cr-policy-network-indicator>
- </div>
+ </template>
<!-- Editable String property value -->
- <template is="dom-if" if="[[isEditable_(
- item, 'String', propertyDict, editFieldTypes)]]">
+ <template is="dom-if" restamp
+ if="[[isEditTypeInput_(item, propertyDict, editFieldTypes)]]">
<paper-input-container no-label-float>
<input id="[[item]]" is="iron-input" slot="input"
+ type="[[getEditInputType_(item, editFieldTypes)]]"
value="[[getPropertyValue_(item, prefix, propertyDict)]]"
on-change="onValueChange_">
</paper-input-container>
</template>
- <!-- Editable Password property value -->
- <template is="dom-if" if="[[isEditable_(
- item, 'Password', propertyDict, editFieldTypes)]]">
- <paper-input-container no-label-float>
- <input id="[[item]]" is="iron-input" type="password" slot="input"
- value="[[getPropertyValue_(item, prefix, propertyDict)]]"
- on-change="onValueChange_">
- </paper-input-container>
- </template>
- <!-- TODO(stevenjb): Support other types. -->
+ <!-- TODO(stevenjb): Support other types (number, boolean)? -->
</div>
</template>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
index f333386cb78..3362979cf20 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
@@ -34,6 +34,8 @@ Polymer({
* Edit type of editable fields. May contain a property for any field in
* |fields|. Other properties will be ignored. Property values can be:
* 'String' - A text input will be displayed.
+ * 'StringArray' - A text input will be displayed that expects a comma
+ * separated list of strings.
* 'Password' - A string with input type = password.
* TODO(stevenjb): Support types with custom validation, e.g. IPAddress.
* TODO(stevenjb): Support 'Number'.
@@ -64,17 +66,17 @@ Polymer({
onValueChange_: function(event) {
if (!this.propertyDict)
return;
- var field = event.target.id;
- var curValue = this.get(field, this.propertyDict);
- if (typeof curValue == 'object') {
+ var key = event.target.id;
+ var curValue = this.get(key, this.propertyDict);
+ if (typeof curValue == 'object' && !Array.isArray(curValue)) {
// Extract the property from an ONC managed dictionary.
curValue = CrOnc.getActiveValue(
/** @type {!CrOnc.ManagedProperty} */ (curValue));
}
- var newValue = event.target.value;
+ var newValue = this.getValueFromEditField_(key, event.target.value);
if (newValue == curValue)
return;
- this.fire('property-change', {field: field, value: newValue});
+ this.fire('property-change', {field: key, value: newValue});
},
/**
@@ -119,19 +121,68 @@ Polymer({
/**
* @param {string} key The property key.
- * @param {string} type The field type.
* @param {!Object} propertyDict
- * @param {!Object} editFieldTypes
* @return {boolean}
* @private
*/
- isEditable_: function(key, type, propertyDict, editFieldTypes) {
+ isPropertyEditable_: function(key, propertyDict) {
var property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
this.get(key, propertyDict));
- if (this.isNetworkPolicyEnforced(property))
+ if (property === undefined) {
+ // Unspecified properties in policy configurations are not user
+ // modifiable. https://crbug.com/819837.
+ var source = propertyDict.Source;
+ return source != 'UserPolicy' && source != 'DevicePolicy';
+ }
+ return !this.isNetworkPolicyEnforced(property);
+ },
+
+ /**
+ * @param {string} key The property key.
+ * @param {!Object} editFieldTypes
+ * @return {boolean}
+ * @private
+ */
+ isEditTypeAny_: function(key, editFieldTypes) {
+ return editFieldTypes[key] !== undefined;
+ },
+
+ /**
+ * @param {string} key The property key.
+ * @param {!Object} propertyDict
+ * @param {!Object} editFieldTypes
+ * @return {boolean}
+ * @private
+ */
+ isEditTypeInput_: function(key, propertyDict, editFieldTypes) {
+ if (!this.isPropertyEditable_(key, propertyDict))
return false;
var editType = editFieldTypes[key];
- return editType !== undefined && (type == '' || editType == type);
+ return editType == 'String' || editType == 'StringArray' ||
+ editType == 'Password';
+ },
+
+ /**
+ * @param {string} key The property key.
+ * @param {!Object} editFieldTypes
+ * @return {string}
+ * @private
+ */
+ getEditInputType_: function(key, editFieldTypes) {
+ return editFieldTypes[key] == 'Password' ? 'password' : 'text';
+ },
+
+ /**
+ * @param {string} key The property key.
+ * @param {!Object} propertyDict
+ * @param {!Object} editFieldTypes
+ * @return {boolean}
+ * @private
+ */
+ isEditable_: function(key, propertyDict, editFieldTypes) {
+ if (!this.isPropertyEditable_(key, propertyDict))
+ return false;
+ return this.isEditTypeAny_(key, editFieldTypes);
},
/**
@@ -141,7 +192,13 @@ Polymer({
* @private
*/
getProperty_: function(key, propertyDict) {
- return this.get(key, propertyDict);
+ var property = this.get(key, propertyDict);
+ if (property === undefined && propertyDict.Source) {
+ // Provide an empty property object with the network policy source.
+ // See https://crbug.com/819837 for more info.
+ return {Effective: propertyDict.Source};
+ }
+ return property;
},
/**
@@ -155,16 +212,20 @@ Polymer({
var value = this.get(key, propertyDict);
if (value === undefined)
return '';
- if (typeof value == 'object') {
+ if (typeof value == 'object' && !Array.isArray(value)) {
// Extract the property from an ONC managed dictionary
value =
CrOnc.getActiveValue(/** @type {!CrOnc.ManagedProperty} */ (value));
}
+ if (Array.isArray(value))
+ return value.join(', ');
+
var customValue = this.getCustomPropertyValue_(key, value);
if (customValue)
return customValue;
if (typeof value == 'number' || typeof value == 'boolean')
return value.toString();
+
assert(typeof value == 'string');
var valueStr = /** @type {string} */ (value);
var oncKey = 'Onc' + prefix + key;
@@ -176,6 +237,20 @@ Polymer({
},
/**
+ * Converts edit field values to the correct edit type.
+ * @param {string} key The property key.
+ * @param {*} fieldValue The value from the field.
+ * @return {*}
+ * @private
+ */
+ getValueFromEditField_(key, fieldValue) {
+ var editType = this.editFieldTypes[key];
+ if (editType == 'StringArray')
+ return fieldValue.toString().split(/, */);
+ return fieldValue;
+ },
+
+ /**
* @param {string} key The property key.
* @param {*} value The property value.
* @return {string} The text to display for the property value. If the key
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
index 7dd7aeb8fe8..400ca41a008 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
@@ -208,7 +208,8 @@ Polymer({
// Set the Web Proxy Auto Discovery URL.
var ipv4 =
CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
- this.WPAD_ = (ipv4 && ipv4.WebProxyAutoDiscoveryUrl) || '';
+ this.WPAD_ = (ipv4 && ipv4.WebProxyAutoDiscoveryUrl) ||
+ this.i18n('networkProxyWpadNone');
this.setProxyAsync_(proxy);
},
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 45101bfbc39..0cff8dd8bec 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
@@ -17,6 +17,10 @@
<dom-module id="network-siminfo">
<template>
<style include="network-shared iron-flex">
+ :host {
+ cursor: default
+ }
+
iron-icon {
-webkit-margin-end: 10px;
}
@@ -43,6 +47,7 @@
paper-toggle-button {
-webkit-margin-start: var(--cr-button-edge-spacing);
+ @apply --cr-actionable;
}
</style>
@@ -85,7 +90,7 @@
</div>
<!-- Enter PIN dialog -->
- <dialog is="cr-dialog" id="enterPinDialog" close-text="[[i18n('close')]]"
+ <cr-dialog id="enterPinDialog" close-text="[[i18n('close')]]"
on-cancel="onEnterPinDialogCancel_"
on-close="onEnterPinDialogClose_">
<div slot="title">[[i18n('networkSimEnterPinTitle')]]</div>
@@ -104,10 +109,10 @@
[[i18n('networkSimEnter')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
<!-- Change PIN dialog -->
- <dialog is="cr-dialog" id="changePinDialog" close-text="[[i18n('close')]]"
+ <cr-dialog id="changePinDialog" close-text="[[i18n('close')]]"
on-close="onChangePinDialogClose_">
<div slot="title">[[i18n('networkSimChangePinTitle')]]</div>
<div slot="body">
@@ -131,10 +136,10 @@
[[i18n('networkSimChange')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
<!-- Unlock PIN dialog -->
- <dialog is="cr-dialog" id="unlockPinDialog" close-text="[[i18n('close')]]"
+ <cr-dialog id="unlockPinDialog" close-text="[[i18n('close')]]"
on-close="onUnlockPinDialogClose_">
<div slot="title">[[i18n('networkSimLockedTitle')]]</div>
<div slot="body">
@@ -152,10 +157,10 @@
[[i18n('networkSimUnlock')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
<!-- Unlock PUK dialog -->
- <dialog is="cr-dialog" id="unlockPukDialog" close-text="[[i18n('close')]]"
+ <cr-dialog id="unlockPukDialog" close-text="[[i18n('close')]]"
on-close="onUnlockPinDialogClose_">
<div slot="title">[[i18n('networkSimLockedTitle')]]</div>
<div slot="body">
@@ -185,7 +190,7 @@
[[i18n('networkSimUnlock')]]
</paper-button>
</div>
- </dialog>
+ </cr-dialog>
</template>
<script src="network_siminfo.js"></script>
</dom-module>
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 668656ec4c4..0a4cfa1fb9d 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
@@ -5,7 +5,6 @@
/**
* @fileoverview Polymer element for displaying and modifying cellular sim info.
*/
-(function() {
/** @enum {string} */
var ErrorType = {
@@ -17,6 +16,8 @@ var ErrorType = {
INVALID_PUK: 'invalid-puk'
};
+(function() {
+
var PIN_MIN_LENGTH = 4;
var PUK_MIN_LENGTH = 8;
var TOGGLE_DEBOUNCE_MS = 500;
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
new file mode 100644
index 00000000000..c027d4cac4f
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn
@@ -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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":pin_keyboard",
+ ]
+}
+
+js_library("pin_keyboard") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/paper-button:paper-button-extracted",
+ "//third_party/polymer/v1_0/components-chromium/paper-input:paper-input-extracted",
+ "//ui/webui/resources/js:i18n_behavior",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
index ad554340880..5e069a548b8 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
@@ -56,11 +56,24 @@
margin-bottom: 6px;
}
- .backspace-button-container {
+ #backspaceButton {
+ color: var(--pin-keyboard-backspace-color, #000);
+ left: 0;
+ opacity: var(--pin-keyboard-backspace-opacity, --dark-primary-opacity);
+ padding: 14px;
+ position: absolute;
+ top: 0;
+ }
+
+ #backspaceButton[disabled] {
+ opacity: 0.34;
+ }
+
+ #backspaceButtonContainer {
position: relative;
}
- .backspace-button-container paper-ripple {
+ #backspaceButtonContainer paper-ripple {
left: var(--pin-keyboard-backspace-paper-ripple-offset, 0);
top: var(--pin-keyboard-backspace-paper-ripple-offset, 0);
}
@@ -84,19 +97,6 @@
@apply --pin-keyboard-digit-button;
}
- .digit-button.backspace-button {
- color: var(--pin-keyboard-backspace-color, #000);
- left: 0;
- opacity: var(--pin-keyboard-backspace-opacity, --dark-primary-opacity);
- padding: 14px;
- position: absolute;
- top: 0;
- }
-
- .digit-button.backspace-button:not([has-content]) {
- opacity: 0.34;
- }
-
.digit-button inner-text {
display: flex;
flex-direction: column;
@@ -169,7 +169,7 @@
}
</style>
- <div id="root" on-contextmenu="onContextMenu_">
+ <div id="root" on-contextmenu="onContextMenu_" on-tap="focusInput_">
<div id="pinInputDiv" class="row">
<paper-input id="pinInput" type="password" no-label-float
value="[[value]]"
@@ -247,9 +247,9 @@
<inner-text class="letter">+</inner-text>
<paper-ripple>
</paper-button>
- <div class="backspace-button-container">
- <paper-icon-button class="digit-button backspace-button"
- has-content$="[[hasInput_(value)]]"
+ <div id="backspaceButtonContainer">
+ <paper-icon-button id="backspaceButton" class="digit-button"
+ disabled$="[[!hasInput_(value)]]"
icon="pin-keyboard:backspace"
on-pointerdown="onBackspacePointerDown_"
on-pointerout="clearAndReset_"
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 2ebcaaf4724..8ffadaa42bd 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
@@ -197,6 +197,17 @@ Polymer({
},
/**
+ * Transfers focus to the input. Called when a non button element on the
+ * PIN button area is clicked to prevent focus from leaving the input.
+ */
+ focusInput_: function() {
+ // Focus the input and place the selected region to its exact previous
+ // location, as this function will not be called by something that will also
+ // modify the input value.
+ this.focus(this.selectionStart_, this.selectionEnd_);
+ },
+
+ /**
* Called when a keypad number has been tapped.
* @param {Event} event The event object.
* @private
@@ -372,7 +383,7 @@ Polymer({
* @private
*/
hasInput_: function(value) {
- return value.length > 0;
+ return value.length > 0 && this.selectionStart_ > 0;
},
/**
diff --git a/chromium/ui/webui/resources/cr_elements/BUILD.gn b/chromium/ui/webui/resources/cr_elements/BUILD.gn
new file mode 100644
index 00000000000..b87727d5ef5
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/BUILD.gn
@@ -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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+group("closure_compile") {
+ deps = [
+ ":cr_elements_resources",
+ "chromeos/cr_picture:closure_compile",
+ "chromeos/network:closure_compile",
+ "cr_action_menu:closure_compile",
+ "cr_dialog:closure_compile",
+ "cr_drawer:closure_compile",
+ "cr_expand_button:closure_compile",
+ "cr_link_row:closure_compile",
+ "cr_profile_avatar_selector:closure_compile",
+ "cr_toast:closure_compile",
+ "cr_toggle:closure_compile",
+ "policy:closure_compile",
+ ]
+}
+
+js_type_check("cr_elements_resources") {
+ deps = [
+ ":cr_container_shadow_behavior",
+ ":cr_scrollable_behavior",
+ ]
+}
+
+js_library("cr_scrollable_behavior") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted",
+ ]
+}
+
+js_library("cr_container_shadow_behavior") {
+}
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 e3bae6770d0..cad6349a0aa 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
@@ -1,9 +1,19 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
+# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_camera",
+ ":cr_picture_list",
+ ":cr_picture_pane",
+ ":cr_picture_types",
+ ":cr_png_behavior",
+ ]
+}
+
js_library("cr_camera") {
deps = [
":cr_png_behavior",
@@ -23,6 +33,7 @@ js_library("cr_picture_pane") {
deps = [
":cr_camera",
":cr_picture_types",
+ ":cr_png_behavior",
]
}
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html
index 15d10cfbe0d..9a5c63cb177 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html
@@ -147,18 +147,22 @@
<!-- Empty div for even 'space-between' justification -->
</div>
<div>
- <button is="paper-icon-button-light" id="takePhoto" tabindex="1"
- title="[[getTakePhotoLabel_(videomode, takePhotoLabel,
- captureVideoLabel)]]" on-tap="takePhoto"
- disabled="[[!cameraOnline_]]">
- </button>
+ <paper-icon-button-light>
+ <button id="takePhoto" tabindex="1"
+ title="[[getTakePhotoLabel_(videomode, takePhotoLabel,
+ captureVideoLabel)]]" on-tap="takePhoto"
+ disabled="[[!cameraOnline_]]">
+ </button>
+ </paper-icon-button-light>
</div>
<div>
- <button is="paper-icon-button-light" id="switchMode" tabindex="2"
- title="[[getSwitchModeLabel_(videomode, switchModeToCameraLabel,
- switchModeToVideoLabel)]]" on-tap="onTapSwitchMode_"
- disabled="[[!cameraOnline_]]" hidden="[[!videoModeEnabled]]">
- </button>
+ <paper-icon-button-light hidden="[[!videoModeEnabled]]">
+ <button id="switchMode" tabindex="2"
+ title="[[getSwitchModeLabel_(videomode, switchModeToCameraLabel,
+ switchModeToVideoLabel)]]" on-tap="onTapSwitchMode_"
+ disabled="[[!cameraOnline_]]">
+ </button>
+ </paper-icon-button-light>
</div>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
index 4abd85b329f..607ac714d98 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
@@ -67,10 +67,12 @@
<img id="image" alt="[[previewAltText]]" src="[[getImgSrc_(imageUrl)]]"
data-show-discard$="[[showDiscard_(imageType)]]">
<div id="discard" hidden="[[!showDiscard_(imageType)]]">
- <button is="paper-icon-button-light" id="discardImage"
- class="icon-delete-white" title="[[discardImageLabel]]"
- on-tap="onTapDiscardImage_">
- </button>
+ <paper-icon-button-light class="icon-delete-white">
+ <button id="discardImage"
+ title="[[discardImageLabel]]"
+ on-tap="onTapDiscardImage_">
+ </button>
+ </paper-icon-button-light>
</div>
</div>
<template is="dom-if" if="[[cameraActive_]]">
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn b/chromium/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
new file mode 100644
index 00000000000..78a6ed2b6bf
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_network_icon",
+ ":cr_network_icon_externs",
+ ":cr_network_list",
+ ":cr_network_list_item",
+ ":cr_network_list_types",
+ ":cr_network_select",
+ ":cr_onc_types",
+ ]
+}
+
+js_library("cr_network_icon") {
+ deps = [
+ ":cr_onc_types",
+ "//ui/webui/resources/js:assert",
+ ]
+}
+
+js_library("cr_network_icon_externs") {
+}
+
+js_library("cr_network_list") {
+ deps = [
+ ":cr_network_list_types",
+ ":cr_onc_types",
+ "//ui/webui/resources/cr_elements:cr_scrollable_behavior",
+ ]
+}
+
+js_library("cr_network_list_item") {
+ deps = [
+ ":cr_network_list_types",
+ ":cr_onc_types",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+ "//ui/webui/resources/js:assert",
+ ]
+}
+
+js_library("cr_network_list_types") {
+ deps = [
+ ":cr_onc_types",
+ ]
+}
+
+js_library("cr_network_select") {
+ deps = [
+ ":cr_network_list_types",
+ ":cr_onc_types",
+ "//ui/webui/resources/js:util",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+}
+
+js_library("cr_onc_types") {
+ deps = [
+ "//ui/webui/resources/js:util",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+}
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
index 4ac2f10fb5a..0b9d6e6341c 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
@@ -158,7 +158,7 @@ Polymer({
networkState.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
}
- var security = networkState.WiFi.Security;
+ var security = CrOnc.getStateOrActiveString(networkState.WiFi.Security);
return !!security && security != 'None';
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
index 8a15cdad6f3..9af9b3a8367 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
@@ -81,10 +81,11 @@
<!-- iron-list captures 'enter' so handle it here explicitly. -->
<iron-a11y-keys keys="enter" on-keys-pressed="fireShowDetails_">
</iron-a11y-keys>
- <button class="subpage-arrow" is="paper-icon-button-light"
- on-tap="fireShowDetails_" tabindex$="[[tabindex]]"
- aria-label$="[[ariaLabel]]">
- </button>
+ <paper-icon-button-light class="subpage-arrow">
+ <button on-tap="fireShowDetails_" tabindex$="[[tabindex]]"
+ aria-label$="[[ariaLabel]]">
+ </button>
+ </paper-icon-button-light>
</template>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
index 26a37dc478f..5b4f6b7326f 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
@@ -153,28 +153,32 @@ Polymer({
this.ensureCellularNetwork_(networkStates);
this.networkStateList_ = networkStates;
var defaultNetwork;
- if (networkStates.length > 0) {
- // Handle an edge case where Ethernet is connecting.
- if (networkStates.length > 1 &&
- networkStates[0].ConnectionState ==
- CrOnc.ConnectionState.CONNECTING &&
- networkStates[1].ConnectionState == CrOnc.ConnectionState.CONNECTED) {
- defaultNetwork = networkStates[1];
- } else {
- defaultNetwork = networkStates[0];
+ for (var i = 0; i < networkStates.length; ++i) {
+ var state = networkStates[i];
+ if (state.ConnectionState == CrOnc.ConnectionState.CONNECTED) {
+ defaultNetwork = state;
+ break;
+ }
+ if (state.ConnectionState == CrOnc.ConnectionState.CONNECTING &&
+ !defaultNetwork) {
+ defaultNetwork = state;
+ // Do not break here in case a non WiFi network is connecting but a
+ // WiFi network is connected.
+ } else if (state.Type == CrOnc.Type.WI_FI) {
+ break; // Non connecting or connected WiFI networks are always last.
}
- } else if (!this.defaultNetworkState_) {
- return; // No change
}
- if (defaultNetwork && this.defaultNetworkState_ &&
- defaultNetwork.GUID == this.defaultNetworkState_.GUID &&
- defaultNetwork.ConnectionState ==
- this.defaultNetworkState_.ConnectionState) {
+ if ((!defaultNetwork && !this.defaultNetworkState_) ||
+ (defaultNetwork && this.defaultNetworkState_ &&
+ defaultNetwork.GUID == this.defaultNetworkState_.GUID &&
+ defaultNetwork.ConnectionState ==
+ this.defaultNetworkState_.ConnectionState)) {
return; // No change to network or ConnectionState
}
- this.defaultNetworkState_ =
+ this.defaultNetworkState_ = defaultNetwork ?
/** @type {!CrOnc.NetworkStateProperties|undefined} */ (
- Object.assign({}, defaultNetwork));
+ Object.assign({}, defaultNetwork)) :
+ undefined;
this.fire('default-network-changed', defaultNetwork);
},
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
index b6671b12291..bab6ac84837 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
@@ -46,7 +46,7 @@ CrOnc.NetworkStateProperties;
/** @typedef {chrome.networkingPrivate.ManagedProperties} */
CrOnc.NetworkProperties;
-/** @typedef {string|number|boolean|Object|Array<Object>} */
+/** @typedef {string|number|boolean|Array<string>|Object|Array<Object>} */
CrOnc.NetworkPropertyType;
/**
@@ -227,7 +227,7 @@ CrOnc.getActiveValue = function(property) {
if (property == undefined)
return undefined;
- if (typeof property != 'object') {
+ if (typeof property != 'object' || Array.isArray(property)) {
console.error(
'getActiveValue called on non object: ' + JSON.stringify(property));
return undefined;
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
new file mode 100644
index 00000000000..9ff9ceb0943
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_action_menu",
+ ]
+}
+
+js_library("cr_action_menu") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:util",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink",
+ ]
+ externs_list = [ "$externs_path/pending.js" ]
+}
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 70acc097ff2..ef6cca6b2f3 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
@@ -8,16 +8,18 @@
<dom-module id="cr-action-menu">
<template>
<style>
- :host {
+ :host dialog {
background-color: white;
border: none;
box-shadow: 0 2px 6px var(--paper-grey-500);
margin: 0;
outline: none;
padding: 8px 0;
+
+ @apply --cr-action-menu-dialog;
}
- :host::backdrop {
+ :host dialog::backdrop {
background-color: transparent;
}
@@ -57,9 +59,11 @@
outline: none;
}
</style>
- <div class="item-wrapper" tabindex="-1" role="menu">
- <slot name="item" id="contentNode"></slot>
- </div>
+ <dialog id="dialog" tabindex="0">
+ <div class="item-wrapper" tabindex="-1" role="menu">
+ <slot name="item" id="contentNode"></slot>
+ </div>
+ </dialog>
</template>
<script src="cr_action_menu.js"></script>
</dom-module>
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 31613726bcc..692a1432a0f 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
@@ -117,7 +117,6 @@ function getDefaultShowConfig() {
Polymer({
is: 'cr-action-menu',
- extends: 'dialog',
/**
* The element which the action menu will be anchored to. Also the element
@@ -146,10 +145,6 @@ Polymer({
/** @private {?ShowAtPositionConfig} */
lastConfig_: null,
- hostAttributes: {
- tabindex: 0,
- },
-
properties: {
// Setting this flag will make the menu listen for content size changes and
// reposition to its anchor accordingly.
@@ -157,6 +152,11 @@ Polymer({
type: Boolean,
value: false,
},
+
+ open: {
+ type: Boolean,
+ value: false,
+ },
},
listeners: {
@@ -170,6 +170,14 @@ Polymer({
this.removeListeners_();
},
+ /**
+ * Exposing internal <dialog> elements for tests.
+ * @return {!HTMLDialogElement}
+ */
+ getDialog: function() {
+ return this.$.dialog;
+ },
+
/** @private */
removeListeners_: function() {
window.removeEventListener('resize', this.boundClose_);
@@ -214,10 +222,10 @@ Polymer({
if (nextOption) {
if (!this.hasMousemoveListener_) {
this.hasMousemoveListener_ = true;
- listenOnce(this, 'mousemove', function(e) {
+ listenOnce(this, 'mousemove', e => {
this.onMouseover_(e);
this.hasMousemoveListener_ = false;
- }.bind(this));
+ });
}
nextOption.focus();
}
@@ -243,7 +251,7 @@ Polymer({
} while (this != target);
// The user moved the mouse off the options. Reset focus to the dialog.
- this.focus();
+ this.$.dialog.focus();
},
/**
@@ -278,11 +286,11 @@ Polymer({
return nextOption;
},
- /** @override */
close: function() {
// Removing 'resize' and 'popstate' listeners when dialog is closed.
this.removeListeners_();
- HTMLDialogElement.prototype.close.call(this);
+ this.$.dialog.close();
+ this.open = false;
if (this.anchorElement_) {
cr.ui.focusWithoutInk(assert(this.anchorElement_));
this.anchorElement_ = null;
@@ -353,7 +361,8 @@ Polymer({
// and so that the dialog is positioned at the top-start corner of the
// document.
this.resetStyle_();
- this.showModal();
+ this.$.dialog.showModal();
+ this.open = true;
config.top += scrollTop;
config.left += scrollLeft;
@@ -375,9 +384,9 @@ Polymer({
/** @private */
resetStyle_: function() {
- this.style.left = '';
- this.style.right = '';
- this.style.top = '0';
+ this.$.dialog.style.left = '';
+ this.$.dialog.style.right = '';
+ this.$.dialog.style.top = '0';
},
/**
@@ -400,20 +409,22 @@ Polymer({
if (rtl)
c.anchorAlignmentX *= -1;
+ const offsetWidth = this.$.dialog.offsetWidth;
var menuLeft = getStartPointWithAnchor(
- left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
+ left, right, offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
if (rtl) {
var menuRight =
- document.scrollingElement.clientWidth - menuLeft - this.offsetWidth;
- this.style.right = menuRight + 'px';
+ document.scrollingElement.clientWidth - menuLeft - offsetWidth;
+ this.$.dialog.style.right = menuRight + 'px';
} else {
- this.style.left = menuLeft + 'px';
+ this.$.dialog.style.left = menuLeft + 'px';
}
var menuTop = getStartPointWithAnchor(
- top, bottom, this.offsetHeight, c.anchorAlignmentY, c.minY, c.maxY);
- this.style.top = menuTop + 'px';
+ top, bottom, this.$.dialog.offsetHeight, c.anchorAlignmentY, c.minY,
+ c.maxY);
+ this.$.dialog.style.top = menuTop + 'px';
},
/**
@@ -421,7 +432,7 @@ Polymer({
*/
addListeners_: function() {
this.boundClose_ = this.boundClose_ || function() {
- if (this.open)
+ if (this.$.dialog.open)
this.close();
}.bind(this);
window.addEventListener('resize', this.boundClose_);
@@ -446,7 +457,7 @@ Polymer({
}
});
- this.resizeObserver_.observe(this);
+ this.resizeObserver_.observe(this.$.dialog);
}
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn
new file mode 100644
index 00000000000..2394d60fabb
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_dialog",
+ ]
+}
+
+js_library("cr_dialog") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/paper-icon-button:paper-icon-button-extracted",
+ "//ui/webui/resources/js:assert",
+ ]
+ externs_list = [ "$externs_path/web_animations.js" ]
+}
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 68cb78ff83f..78c091b52ee 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
@@ -9,7 +9,7 @@
<dom-module id="cr-dialog">
<template>
<style include="cr-hidden-style cr-icons">
- :host {
+ dialog {
--scroll-border: 1px solid var(--paper-grey-300);
border: 0;
border-radius: 2px;
@@ -21,9 +21,10 @@
padding: 0;
top: 50%;
width: 512px;
+ @apply --cr-dialog-native;
}
- :host([open]) #content-wrapper {
+ dialog[open] #content-wrapper {
/* Keep max-height within viewport, and flex content accordingly. */
display: flex;
flex-direction: column;
@@ -39,7 +40,7 @@
flex-shrink: 0;
}
- :host::backdrop {
+ dialog::backdrop {
background-color: rgba(0, 0, 0, 0.6);
bottom: 0;
left: 0;
@@ -108,7 +109,7 @@
outline: none;
}
- #close {
+ #closeContainer {
--layout-inline: {
display: flex;
};
@@ -116,40 +117,43 @@
-webkit-margin-end: 4px;
align-self: flex-start;
margin-top: 4px;
- padding: 10px; /* Makes the actual icon 16x16. */
@apply --cr-dialog-close-image;
}
- #close:hover {
+ #closeContainer:hover {
@apply --cr-dialog-close-image-hover;
}
- #close:active {
+ #closeContainer:active {
@apply --cr-dialog-close-image-active;
}
</style>
- <!-- This wrapper is necessary, such that the "pulse" animation is not
- erroneously played when the user clicks on the outer-most scrollbar. -->
- <div id="content-wrapper">
- <div class="top-container">
- <div class="title-container" tabindex="-1">
- <slot name="title"></slot>
+ <dialog id="dialog">
+ <!-- This wrapper is necessary, such that the "pulse" animation is not
+ erroneously played when the user clicks on the outer-most scrollbar. -->
+ <div id="content-wrapper">
+ <div class="top-container">
+ <div class="title-container" tabindex="-1">
+ <slot name="title"></slot>
+ </div>
+ <paper-icon-button-light id="closeContainer" class="icon-clear"
+ hidden$="[[noCancel]]">
+ <button id="close" aria-label$="[[closeText]]"
+ on-tap="cancel" on-keypress="onCloseKeypress_">
+ </button>
+ </paper-icon-button-light>
</div>
- <button is="paper-icon-button-light" class="icon-clear" id="close"
- aria-label$="[[closeText]]" hidden$="[[noCancel]]" on-tap="cancel"
- on-keypress="onCloseKeypress_">
- </button>
- </div>
- <slot name="header"></slot>
- <div class="body-container">
- <span id="bodyTopMarker"></span>
- <slot name="body"></slot>
- <span id="bodyBottomMarker"></span>
+ <slot name="header"></slot>
+ <div class="body-container">
+ <span id="bodyTopMarker"></span>
+ <slot name="body"></slot>
+ <span id="bodyBottomMarker"></span>
+ </div>
+ <slot name="button-container"></slot>
+ <slot name="footer"></slot>
</div>
- <slot name="button-container"></slot>
- <slot name="footer"></slot>
- </div>
+ </dialog>
</template>
<script src="cr_dialog.js"></script>
</dom-module>
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 59ee2f6e179..554d846387d 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
@@ -6,16 +6,29 @@
* @fileoverview 'cr-dialog' is a component for showing a modal dialog. If the
* dialog is closed via close(), a 'close' event is fired. If the dialog is
* canceled via cancel(), a 'cancel' event is fired followed by a 'close' event.
- * Additionally clients can inspect the dialog's |returnValue| property inside
+ *
+ * Additionally clients can get a reference to the internal native <dialog> via
+ * calling getNative() and inspecting the |returnValue| property inside
* the 'close' event listener to determine whether it was canceled or just
* closed, where a truthy value means success, and a falsy value means it was
* canceled.
+ *
+ * Note that <cr-dialog> wrapper itself always has 0x0 dimensions, and
+ * specifying width/height on <cr-dialog> directly will have no effect on the
+ * internal native <dialog>. Instead use the --cr-dialog-native mixin to specify
+ * width/height (as well as other available mixins to style other parts of the
+ * dialog contents).
*/
Polymer({
is: 'cr-dialog',
- extends: 'dialog',
properties: {
+ open: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
+
/**
* Alt-text for the dialog close button.
*/
@@ -63,7 +76,7 @@ Polymer({
// If the active history entry changes (i.e. user clicks back button),
// all open dialogs should be cancelled.
window.addEventListener('popstate', function() {
- if (!this.ignorePopstate && this.open)
+ if (!this.ignorePopstate && this.$.dialog.open)
this.cancel();
}.bind(this));
@@ -77,7 +90,7 @@ Polymer({
/** @override */
attached: function() {
var mutationObserverCallback = function() {
- if (this.open)
+ if (this.$.dialog.open)
this.addIntersectionObserver_();
else
this.removeIntersectionObserver_();
@@ -85,7 +98,7 @@ Polymer({
this.mutationObserver_ = new MutationObserver(mutationObserverCallback);
- this.mutationObserver_.observe(this, {
+ this.mutationObserver_.observe(this.$.dialog, {
attributes: true,
attributeFilter: ['open'],
});
@@ -146,17 +159,20 @@ Polymer({
}
},
+ showModal: function() {
+ this.$.dialog.showModal();
+ this.open = this.$.dialog.open;
+ },
+
cancel: function() {
this.fire('cancel');
- HTMLDialogElement.prototype.close.call(this, '');
+ this.$.dialog.close();
+ this.open = this.$.dialog.open;
},
- /**
- * @param {string=} opt_returnValue
- * @override
- */
- close: function(opt_returnValue) {
- HTMLDialogElement.prototype.close.call(this, 'success');
+ close: function() {
+ this.$.dialog.close('success');
+ this.open = this.$.dialog.open;
},
/**
@@ -169,6 +185,16 @@ Polymer({
e.stopPropagation();
},
+ /**
+ * Expose the inner native <dialog> for some rare cases where it needs to be
+ * directly accessed (for example to programmatically setheight/width, which
+ * would not work on the wrapper).
+ * @return {!HTMLDialogElement}
+ */
+ getNative: function() {
+ return this.$.dialog;
+ },
+
/** @return {!PaperIconButtonElement} */
getCloseButton: function() {
return this.$.close;
@@ -210,7 +236,7 @@ Polymer({
if (e.button != 0 || e.composedPath()[0].tagName !== 'DIALOG')
return;
- this.animate(
+ this.$.dialog.animate(
[
{transform: 'scale(1)', offset: 0},
{transform: 'scale(1.02)', offset: 0.4},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
new file mode 100644
index 00000000000..5ca559e9de2
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_drawer",
+ ]
+}
+
+js_library("cr_drawer") {
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
index e2e1cb0529e..78548247952 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
@@ -1,10 +1,11 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<dom-module id="cr-drawer">
<template>
<style>
- :host {
+ :host dialog {
--drawer-width: 256px;
--transition-timing: 200ms ease;
background-color: #fff;
@@ -20,27 +21,27 @@
width: var(--drawer-width);
}
- :host,
+ :host dialog,
#container {
height: 100%;
word-break: break-word;
}
- :host(.opening) {
+ :host(.opening) dialog {
left: 0;
}
- :host([align=rtl]) {
+ :host([align=rtl]) dialog {
left: auto;
right: calc(-1 * var(--drawer-width));
transition: right var(--transition-timing);
}
- :host(.opening[align=rtl]) {
+ :host(.opening[align=rtl]) dialog {
right: 0;
}
- :host::backdrop {
+ :host dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
bottom: 0;
left: 0;
@@ -51,7 +52,7 @@
transition: opacity var(--transition-timing);
}
- :host(.opening)::backdrop {
+ :host(.opening) dialog::backdrop {
opacity: 1;
}
@@ -70,10 +71,12 @@
overflow: auto;
}
</style>
- <div id="container" on-tap="onContainerTap_">
- <div class="drawer-header" tabindex="-1">[[heading]]</div>
- <slot></slot>
- </div>
+ <dialog id="dialog" on-cancel="onDialogCancel_" on-tap="onDialogTap_">
+ <div id="container" on-tap="onContainerTap_">
+ <div class="drawer-header" tabindex="-1">[[heading]]</div>
+ <slot></slot>
+ </div>
+ </dialog>
</template>
</dom-module>
<script src="cr_drawer.js"></script>
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 44b5180a7b5..cb06e3576ab 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
@@ -4,14 +4,13 @@
Polymer({
is: 'cr-drawer',
- extends: 'dialog',
properties: {
heading: String,
- /** Enables notifications for |Dialog.open|. */
open: {
type: Boolean,
+ // Enables 'open-changed' events.
notify: true,
},
@@ -24,14 +23,12 @@ Polymer({
},
listeners: {
- 'cancel': 'onDialogCancel_',
- 'tap': 'onDialogTap_',
'transitionend': 'onDialogTransitionEnd_',
},
/** Toggles the drawer open and close. */
toggle: function() {
- if (this.open)
+ if (this.$.dialog.open)
this.closeDrawer();
else
this.openDrawer();
@@ -39,15 +36,16 @@ Polymer({
/** Shows drawer and slides it into view. */
openDrawer: function() {
- if (!this.open) {
- this.showModal();
+ if (!this.$.dialog.open) {
+ this.$.dialog.showModal();
+ this.open = true;
this.classList.add('opening');
}
},
/** Slides the drawer away, then closes it after the transition has ended. */
closeDrawer: function() {
- if (this.open) {
+ if (this.$.dialog.open) {
this.classList.remove('opening');
this.classList.add('closing');
}
@@ -88,7 +86,8 @@ Polymer({
onDialogTransitionEnd_: function() {
if (this.classList.contains('closing')) {
this.classList.remove('closing');
- this.close();
+ this.$.dialog.close();
+ this.open = false;
}
},
});
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
new file mode 100644
index 00000000000..14021b10ab6
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_expand_button",
+ ]
+}
+
+js_library("cr_expand_button") {
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
index e31345821ed..56fccded4dc 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
@@ -7,10 +7,11 @@
<template>
<style include="cr-icons cr-shared-style">
:host([disabled]) {
+ opacity: 0.65;
pointer-events: none;
}
- button[is=paper-icon-button-light] {
+ paper-icon-button-light {
@apply --cr-paper-icon-button-margin;
}
@@ -25,11 +26,12 @@
</style>
<div id="outer" on-tap="toggleExpand_">
<div id="label" on-tap="toggleExpand_"><slot></slot></div>
- <button is="paper-icon-button-light" class$="[[iconName_(expanded)]]"
- toggles active="{{expanded}}" disabled="[[disabled]]"
- aria-label$="[[alt]]" aria-pressed$="[[getAriaPressed_(expanded)]]"
- tabindex$="[[tabIndex]]">
- </button>
+ <paper-icon-button-light class$="[[iconName_(expanded)]]">
+ <button toggles active="{{expanded}}" disabled="[[disabled]]"
+ aria-label$="[[alt]]" aria-pressed$="[[getAriaPressed_(expanded)]]"
+ tabindex$="[[tabIndex]]">
+ </button>
+ </paper-icon-button-light>
</div>
</template>
<script src="cr_expand_button.js"></script>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
index f8dc56c8a7f..0db9b898093 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -4,12 +4,16 @@
<dom-module id="cr-icons">
<template>
<style>
- :host-context([dir=rtl]) :-webkit-any(
- button[is='paper-icon-button-light'], .cr-icon) {
+ :host-context([dir=rtl]) :-webkit-any(paper-icon-button-light, .cr-icon) {
transform: scaleX(-1); /* Invert X: flip on the Y axis (aka mirror). */
}
- button[is='paper-icon-button-light'],
+ paper-icon-button-light paper-ripple {
+ color: currentColor;
+ opacity: 0.6;
+ }
+
+ paper-icon-button-light,
.cr-icon {
@apply --cr-paper-icon-button-margin;
background-position: center;
@@ -21,99 +25,80 @@
width: var(--cr-icon-ripple-size);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).no-overlap {
+ :-webkit-any(paper-icon-button-light, .cr-icon).no-overlap {
margin-left: 0;
margin-right: 0;
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-arrow-back {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
background-image: url(../images/icon_arrow_back.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-cancel {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
background-image: url(../images/icon_cancel.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-cancel-toolbar {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel-toolbar {
background-image: url(../images/icon_cancel_toolbar.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-clear {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
background-image: url(../images/icon_clear.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-delete-gray {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
background-image: url(../images/icon_delete_gray.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-delete-white {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-white {
background-image: url(../images/icon_delete_white.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-expand-less {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
background-image: url(../images/icon_expand_less.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-expand-more {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
background-image: url(../images/icon_expand_more.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-external {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-external {
background-image: url(../images/open_in_new.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-menu-white {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-menu-white {
background-image: url(../images/icon_menu_white.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-more-vert {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
background-image: url(../images/icon_more_vert.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-refresh {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
background-image: url(../images/icon_refresh.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-settings {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
background-image: url(../images/icon_settings.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-search {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
background-image: url(../images/icon_search.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-arrow-dropdown {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
background-image: url(../images/icon_arrow_dropdown.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).subpage-arrow {
+ :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
background-image: url(../images/arrow_right.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-visibility {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
background-image: url(../images/icon_visibility.svg);
}
- :-webkit-any(button[is='paper-icon-button-light'],
- .cr-icon).icon-visibility-off {
+ :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
background-image: url(../images/icon_visibility_off.svg);
}
</style>
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
new file mode 100644
index 00000000000..e681565722f
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_lazy_render",
+ ]
+}
+
+js_library("cr_lazy_render") {
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html
index 9dffa4c9557..be956c79fa7 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.html
@@ -1,3 +1,8 @@
<link rel="import" href="chrome://resources/html/polymer.html">
-<script src="cr_lazy_render.js"></script>
+<dom-module id="cr-lazy-render">
+ <template>
+ <slot></slot>
+ </template>
+ <script src="cr_lazy_render.js"></script>
+</dom-module>
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 8fac4f477e2..48fd9acb414 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
@@ -7,16 +7,20 @@
* cr-lazy-render is a simple variant of dom-if designed for lazy rendering
* of elements that are accessed imperatively.
* Usage:
- * <template is="cr-lazy-render" id="menu">
- * <heavy-menu></heavy-menu>
- * </template>
+ * <cr-lazy-render id="menu">
+ * <template>
+ * <heavy-menu></heavy-menu>
+ * </template>
+ * </cr-lazy-render>
*
* this.$.menu.get().show();
+ *
+ * TODO(calamity): Use Polymer.Templatize instead of inheriting the
+ * Polymer.Templatizer behavior once Polymer 2.0 is available.
*/
Polymer({
is: 'cr-lazy-render',
- extends: 'template',
behaviors: [Polymer.Templatizer],
@@ -43,8 +47,9 @@ Polymer({
/** @private */
render_: function() {
- if (!this.ctor)
- this.templatize(this);
+ var template = this.getContentChildren()[0];
+ if (!template.ctor)
+ this.templatize(template);
var parentNode = this.parentNode;
if (parentNode && !this.child_) {
var instance = this.stamp({});
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
new file mode 100644
index 00000000000..d487f4132e0
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_link_row",
+ ]
+}
+
+js_library("cr_link_row") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/iron-behaviors:iron-button-state-extracted",
+ "//third_party/polymer/v1_0/components-chromium/paper-behaviors:paper-ripple-behavior-extracted",
+ ]
+}
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 97bb3cc66a7..f1beac343f1 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
@@ -12,12 +12,16 @@
:host {
align-items: center;
align-self: stretch;
+ display: block;
+ flex: 1;
+ }
+
+ :host > button {
background: none;
border: none;
color: inherit;
cursor: pointer;
display: flex;
- flex: 1;
font-family: inherit;
font-size: 100%; /* Specifically for Mac OSX, harmless elsewhere. */
line-height: 154%; /* 20px. */
@@ -25,6 +29,7 @@
min-height: var(--cr-section-min-height);
outline: none;
padding: 0 var(--cr-section-padding);
+ width: 100%;
}
:host([disabled]) {
@@ -70,15 +75,17 @@
font-weight: 400;
}
</style>
- <div id="outer" noSubLabel$="[[!subLabel]]">
- <div id="labelWrapper" hidden="[[!label]]">
- <div id="label" class="label">[[label]]</div>
- <div id="subLabel" class="secondary label">[[subLabel]]</div>
- </div>
- <slot></slot>
- <div id="icon" class$="cr-icon [[iconClass]]" aria-hidden="true">
+ <button disabled="[[disabled]]">
+ <div id="outer" noSubLabel$="[[!subLabel]]">
+ <div id="labelWrapper" hidden="[[!label]]">
+ <div id="label" class="label">[[label]]</div>
+ <div id="subLabel" class="secondary label">[[subLabel]]</div>
+ </div>
+ <slot></slot>
+ <div id="icon" class$="cr-icon [[iconClass]]" aria-hidden="true">
+ </div>
</div>
- </div>
+ </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 c8f16a67b1d..b94008121cb 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
@@ -12,7 +12,6 @@
*/
Polymer({
is: 'cr-link-row',
- extends: 'button',
behaviors: [Polymer.PaperRippleBehavior],
@@ -26,6 +25,11 @@ Polymer({
/* Value used for noSubLabel attribute. */
value: '',
},
+
+ disabled: {
+ type: Boolean,
+ reflectToAttribute: true,
+ },
},
listeners: {
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
new file mode 100644
index 00000000000..d86f6b5d8dd
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_profile_avatar_selector",
+ ":cr_profile_avatar_selector_grid",
+ ]
+}
+
+js_library("cr_profile_avatar_selector") {
+ deps = [
+ ":cr_profile_avatar_selector_grid",
+ "//ui/webui/resources/js:icon",
+ ]
+}
+
+js_library("cr_profile_avatar_selector_grid") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:util",
+ ]
+}
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 bc13ad1d5d6..3a075c1e755 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
@@ -43,7 +43,8 @@
<cr-profile-avatar-selector-grid id="avatar-grid"
ignore-modified-key-events="[[ignoreModifiedKeyEvents]]">
<template is="dom-repeat" items="[[avatars]]">
- <paper-button class="avatar" title="[[item.label]]"
+ <paper-button class$="avatar [[getSelectedClass_(item.selected)]]"
+ title="[[item.label]]"
style$="background-image: [[getIconImageSet_(item.url)]]"
on-tap="onAvatarTap_">
</paper-button>
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 2716e934e6a..ea4098ddd68 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
@@ -10,7 +10,8 @@
/**
* @typedef {{url: string,
* label: string,
- * isGaiaAvatar: (boolean|undefined)}}
+ * isGaiaAvatar: (boolean|undefined),
+ * selected: (boolean|undefined)}}
*/
let AvatarIcon;
@@ -47,6 +48,13 @@ Polymer({
},
},
+ /** @private */
+ getSelectedClass_: function(isSelected) {
+ // TODO(dpapad): Rename 'iron-selected' to 'selected' now that this CSS
+ // class is not assigned by any iron-* behavior.
+ return isSelected ? 'iron-selected' : '';
+ },
+
/**
* @param {string} iconUrl
* @return {string} A CSS image-set for multiple scale factors.
@@ -61,13 +69,14 @@ Polymer({
* @private
*/
onAvatarTap_: function(e) {
- // TODO(dpapad): Rename 'iron-selected' to 'selected' now that this CSS
- // class is not assigned by any iron-* behavior.
+ // 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;
},
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
new file mode 100644
index 00000000000..481c4e60be4
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_search_field_behavior",
+ ]
+}
+
+js_library("cr_search_field_behavior") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
new file mode 100644
index 00000000000..1d1fcf225d0
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_toast",
+ ]
+}
+
+js_library("cr_toast") {
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
index f0aa56a5972..91346b54060 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
@@ -4,33 +4,31 @@
<template>
<style>
:host {
- align-items: var(--cr-toast-align-items, center);
- background-color: var(--cr-toast-background-color, #323232);
- border-radius: var(--cr-toast-border-radius, 4px);
- bottom: var(--cr-toast-bottom, 0);
- box-shadow: var(--cr-toast-box-shadow, 0 2px 4px 0 rgba(0, 0, 0, 0.28));
- box-sizing: var(--cr-toast-box-sizing, border-box);
- display: var(--cr-toast-display, flex);
- margin: var(--cr-toast-margin, 24px);
- max-width: var(--cr-toast-max-width, 568px);
- min-height: var(--cr-toast-min-height, 52px);
- min-width: var(--cr-toast-min-width, 288px);
- opacity: var(--cr-toast-opacity-closed, 0);
- padding: var(--cr-toast-padding, 0 24px);
- position: var(--cr-toast-position, fixed);
- transform: var(--cr-toast-transform-closed, translateY(100px));
- transition:
- opacity var(--cr-toast-transition-time-opacity, 300ms),
- transform var(--cr-toast-transition-time-transform, 300ms),
- visibility var(--cr-toast-transition-time-visibility, 300ms);
- visibility: var(--cr-toast-visibility-closed, hidden);
- white-space: var(--cr-toast-white-space, nowrap);
+ align-items: center;
+ background-color: #323232;
+ border-radius: 4px;
+ bottom: 0;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.28);
+ box-sizing: border-box;
+ display: flex;
+ margin: 24px;
+ max-width: 568px;
+ min-height: 52px;
+ min-width: 288px;
+ opacity: 0;
+ padding: 0 24px;
+ position: fixed;
+ transform: translateY(100px);
+ transition: opacity 300ms, transform 300ms, visibility 300ms;
+ visibility: hidden;
+ white-space: nowrap;
+ z-index: 1;
}
:host([open]) {
- opacity: var(--cr-toast-opacity-open, 1);
- transform: var(--cr-toast-transform-open, translateY(0));
- visibility: var(--cr-toast-visibility-open, visible);
+ opacity: 1;
+ transform: translateY(0);
+ visibility: visible;
}
</style>
<slot></slot>
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 bf26149880a..a2bd8d7d24c 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
@@ -20,24 +20,63 @@ Polymer({
},
},
+ observers: ['resetAutoHide_(duration, open)'],
+
/** @private {number|null} */
hideTimeoutId_: null,
- show: function() {
- this.open = true;
+ /**
+ * Cancels existing auto-hide, and sets up new auto-hide.
+ * @private
+ */
+ resetAutoHide_: function() {
+ if (this.hideTimeoutId_ != null) {
+ window.clearTimeout(this.hideTimeoutId_);
+ this.hideTimeoutId_ = null;
+ }
+
+ if (this.open && this.duration != 0) {
+ this.hideTimeoutId_ = window.setTimeout(() => {
+ this.open = false;
+ }, this.duration);
+ }
+ },
- if (!this.duration)
- return;
+ /**
+ * Shows the toast and auto-hides after |this.duration| milliseconds has
+ * passed. If the toast is currently being shown, any preexisting auto-hide
+ * is cancelled and replaced with a new auto-hide.
+ *
+ * If |this.duration| is set to 0, the toast will remain open indefinitely.
+ * The caller is responsible for hiding the toast.
+ *
+ * When |duration| is passed in the non-negative number, |this.duration|
+ * is updated to that value.
+ * @param {number=} duration
+ */
+ show: function(duration) {
+ // |this.resetAutoHide_| is called whenever |this.duration| or |this.open|
+ // is changed. If neither is changed, we will still need to reset auto-hide.
+ let shouldResetAutoHide = true;
- if (this.hideTimeoutId_ != null)
- window.clearTimeout(this.hideTimeoutId_);
+ if (typeof(duration) != 'undefined' && duration >= 0 &&
+ this.duration != duration) {
+ this.duration = duration;
+ shouldResetAutoHide = false;
+ }
- this.hideTimeoutId_ = window.setTimeout(() => {
- this.hide();
- this.hideTimeoutId_ = null;
- }, this.duration);
+ if (!this.open) {
+ this.open = true;
+ shouldResetAutoHide = false;
+ }
+
+ if (shouldResetAutoHide)
+ this.resetAutoHide_();
},
+ /**
+ * Hides the toast.
+ */
hide: function() {
this.open = false;
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn
new file mode 100644
index 00000000000..f484f7463d3
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_toggle",
+ ]
+}
+
+js_library("cr_toggle") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/iron-behaviors:iron-button-state-extracted",
+ "//third_party/polymer/v1_0/components-chromium/paper-behaviors:paper-ripple-behavior-extracted",
+ ]
+ externs_list = [ "$externs_path/pending.js" ]
+}
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 4cf3d472c74..d4d38a789a0 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
@@ -5,7 +5,7 @@
/**
* @fileoverview 'cr-toggle' is a component for showing an on/off switch. It
* fires a 'change' event *only* when its state changes as a result of a user
- * interaction. Besides just tapping the element, its state can be changed by
+ * interaction. Besides just clicking the element, its state can be changed by
* dragging (pointerdown+pointermove) the element towards the desired direction.
*/
Polymer({
@@ -40,7 +40,7 @@ Polymer({
listeners: {
'pointerdown': 'onPointerDown_',
'pointerup': 'onPointerUp_',
- 'tap': 'onTap_',
+ 'click': 'onTap_',
'keypress': 'onKeyPress_',
'focus': 'onFocus_',
'blur': 'onBlur_',
@@ -58,7 +58,7 @@ Polymer({
/**
* Whether the state of the toggle has already taken into account by
- * |pointeremove| handlers. Used in the 'tap' handler.
+ * |pointeremove| handlers. Used in the 'click' handler.
* @private {boolean}
*/
handledInPointerMove_: false,
@@ -136,28 +136,29 @@ Polymer({
/** @private */
onTap_: function(e) {
- // Prevent |tap| event from bubbling. It can cause parents of this elements
- // to erroneously re-toggle this control.
+ // Prevent |click| event from bubbling. It can cause parents of this
+ // elements to erroneously re-toggle this control.
e.stopPropagation();
+ e.preventDefault();
// User gesture has already been taken care of inside |pointermove|
// handlers, Do nothing here.
if (this.handledInPointerMove_)
return;
- // If no pointermove event fired, then user just tapped on the
+ // If no pointermove event fired, then user just clicked on the
// toggle button and therefore it should be toggled.
this.toggleState_(false);
},
/**
- * Whether the host of this element should handle a 'tap' event it received,
- * to be used when tapping on the parent is supposed to toggle the cr-toggle.
+ * Whether the host of this element should handle a 'click' event it received,
+ * to be used when clicking on the parent is supposed to toggle the cr-toggle.
*
* This is necessary to avoid a corner case when pointerdown is initiated
* in cr-toggle, but pointerup happens outside the bounds of cr-toggle, which
- * ends up firing a 'tap' event on the parent (see context at crbug.com/689158
- * and crbug.com/768555).
+ * ends up firing a 'click' event on the parent (see context at
+ * crbug.com/689158 and crbug.com/768555).
* @param {!Event} e
* @return {boolean}
*/
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn
new file mode 100644
index 00000000000..6cefa20d292
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn
@@ -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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_toolbar",
+ ":cr_toolbar_search_field",
+ ":cr_toolbar_selection_overlay",
+ ]
+}
+
+js_library("cr_toolbar_search_field") {
+ deps = [
+ "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field_behavior",
+ ]
+}
+
+js_library("cr_toolbar_selection_overlay") {
+ deps = [
+ "//third_party/polymer/v1_0/components-chromium/paper-button:paper-button-extracted",
+ ]
+}
+
+js_library("cr_toolbar") {
+ deps = [
+ ":cr_toolbar_search_field",
+ ]
+ externs_list = [ "$externs_path/web_animations.js" ]
+}
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 55caed47dda..f1467416180 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
@@ -40,12 +40,10 @@
display: flex;
}
- #menuButton {
+ #menuButtonContainer {
height: 32px;
- margin-bottom: 6px;
- margin-top: 6px;
min-width: 32px;
- padding: 6px;
+ padding: 6px 0;
width: 32px;
}
@@ -130,12 +128,14 @@
<div id="leftSpacer">
<!-- Note: showing #menuPromo relies on this dom-if being [restamp]. -->
<template is="dom-if" if="[[showMenu]]" restamp>
- <button id="menuButton" is="paper-icon-button-light"
- class="icon-menu-white no-overlap"
- on-tap="onMenuTap_"
- title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
- aria-label$="[[menuLabel]]">
- </button>
+ <paper-icon-button-light id="menuButtonContainer"
+ class="icon-menu-white no-overlap">
+ <button id="menuButton"
+ on-tap="onMenuTap_"
+ title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
+ aria-label$="[[menuLabel]]">
+ </button>
+ </paper-icon-button-light>
<template is="dom-if" if="[[showMenuPromo]]">
<div id="menuPromo" role="tooltip">
[[menuPromo]]
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 063e1fd2902..71f389bac92 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
@@ -22,7 +22,7 @@
display: none !important;
}
- button[is='paper-icon-button-light'],
+ paper-icon-button-light,
paper-icon-button {
height: 32px;
margin: 6px;
@@ -153,9 +153,10 @@
autofocus>
</div>
<template is="dom-if" if="[[hasSearchText]]">
- <button is="paper-icon-button-light" class="icon-cancel-toolbar"
- id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_">
- </button>
+ <paper-icon-button-light class="icon-cancel-toolbar">
+ <button id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_">
+ </button>
+ </paper-icon-button-light>
</template>
</template>
<script src="cr_toolbar_search_field.js"></script>
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 3138f473a77..28d494e8b2d 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,11 +1,12 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<dom-module id="cr-toolbar-selection-overlay">
<template>
- <style>
+ <style include="cr-icons">
:host {
-webkit-padding-start: var(--cr-toolbar-field-margin, 0);
display: flex;
@@ -35,7 +36,7 @@
flex: 1;
}
- button {
+ paper-icon-button-light {
-webkit-margin-end: 24px;
-webkit-margin-start: 2px;
height: 36px;
@@ -48,11 +49,11 @@
}
</style>
<div id="overlay-content">
- <button is="paper-icon-button-light"
- on-tap="onClearSelectionTap_"
- title="[[cancelLabel]]">
- <iron-icon icon="cr:clear"></iron-icon>
- </button>
+ <paper-icon-button-light>
+ <button on-tap="onClearSelectionTap_" title="[[cancelLabel]]">
+ <iron-icon icon="cr:clear"></iron-icon>
+ </button>
+ </paper-icon-button-light>
<div id="number-selected">[[selectionLabel]]</div>
<paper-button on-tap="onClearSelectionTap_">
[[cancelLabel]]
diff --git a/chromium/ui/webui/resources/cr_elements/icons.html b/chromium/ui/webui/resources/cr_elements/icons.html
index ccff3013f93..b55baf0f48f 100644
--- a/chromium/ui/webui/resources/cr_elements/icons.html
+++ b/chromium/ui/webui/resources/cr_elements/icons.html
@@ -51,6 +51,7 @@ blurry at 20 px). Please use 20 px icons when available.
<g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
<g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"></path></g>
<g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></g>
+ <g id="security"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"></path></g>
<if expr="chromeos">
<g id="sim-card-alert"><path d="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5 15h-2v-2h2v2zm0-4h-2V8h2v5z"></path></g>
<g id="sim-lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g>
diff --git a/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn
new file mode 100644
index 00000000000..244f3a615eb
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn
@@ -0,0 +1,62 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_policy_indicator",
+ ":cr_policy_indicator_behavior",
+ ":cr_policy_network_behavior",
+ ":cr_policy_network_indicator",
+ ":cr_policy_pref_behavior",
+ ":cr_policy_pref_indicator",
+ ":cr_tooltip_icon",
+ ]
+}
+
+js_library("cr_policy_indicator") {
+ deps = [
+ ":cr_policy_indicator_behavior",
+ "//ui/webui/resources/js:assert",
+ ]
+}
+
+js_library("cr_policy_indicator_behavior") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ ]
+}
+
+js_library("cr_policy_pref_behavior") {
+ deps = [
+ ":cr_policy_indicator_behavior",
+ ]
+ externs_list = [ "$externs_path/settings_private.js" ]
+}
+
+js_library("cr_policy_pref_indicator") {
+ deps = [
+ ":cr_policy_indicator_behavior",
+ ]
+ externs_list = [ "$externs_path/settings_private.js" ]
+}
+
+js_library("cr_policy_network_behavior") {
+ deps = [
+ ":cr_policy_indicator_behavior",
+ "../chromeos/network:cr_onc_types",
+ ]
+}
+
+js_library("cr_policy_network_indicator") {
+ deps = [
+ ":cr_policy_indicator_behavior",
+ ":cr_policy_network_behavior",
+ "../chromeos/network:cr_onc_types",
+ ]
+}
+
+js_library("cr_tooltip_icon") {
+}
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 e8b2bba0d98..5c3ad39d71f 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
@@ -13,6 +13,7 @@
* Chrome OS only strings may be undefined.
* @type {{
* controlledSettingExtension: string,
+ * controlledSettingExtensionWithoutName: string,
* controlledSettingPolicy: string,
* controlledSettingRecommendedMatches: string,
* controlledSettingRecommendedDiffers: string,
@@ -120,7 +121,9 @@ var CrPolicyIndicatorBehavior = {
return ''; // Tooltips may not be defined, e.g. in OOBE.
switch (type) {
case CrPolicyIndicatorType.EXTENSION:
- return CrPolicyStrings.controlledSettingExtension.replace('$1', name);
+ return name.length > 0 ?
+ CrPolicyStrings.controlledSettingExtension.replace('$1', name) :
+ CrPolicyStrings.controlledSettingExtensionWithoutName;
case CrPolicyIndicatorType.PRIMARY_USER:
return CrPolicyStrings.controlledSettingShared.replace('$1', name);
case CrPolicyIndicatorType.OWNER:
diff --git a/chromium/ui/webui/resources/images/fingerprint_failed.svg b/chromium/ui/webui/resources/images/icon_error_outline.svg
index 314ee0c6686..314ee0c6686 100644
--- a/chromium/ui/webui/resources/images/fingerprint_failed.svg
+++ b/chromium/ui/webui/resources/images/icon_error_outline.svg
diff --git a/chromium/ui/webui/resources/js/BUILD.gn b/chromium/ui/webui/resources/js/BUILD.gn
index 75cf392f0b3..b9d148cc795 100644
--- a/chromium/ui/webui/resources/js/BUILD.gn
+++ b/chromium/ui/webui/resources/js/BUILD.gn
@@ -1,9 +1,37 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
+# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+group("closure_compile") {
+ deps = [
+ ":js_resources",
+ "cr:closure_compile",
+ "cr/ui:closure_compile",
+ ]
+}
+
+js_type_check("js_resources") {
+ deps = [
+ ":action_link",
+ ":assert",
+ ":cr",
+ ":event_tracker",
+ ":i18n_behavior",
+ ":i18n_template",
+ ":i18n_template_no_process",
+ ":icon",
+ ":load_time_data",
+ ":parse_html_subset",
+ ":promise_resolver",
+ ":search_highlight_utils",
+ ":util",
+ ":web_ui_listener_behavior",
+ ":webui_listener_tracker",
+ ]
+}
+
js_library("action_link") {
}
@@ -27,6 +55,12 @@ js_library("webui_listener_tracker") {
]
}
+js_library("search_highlight_utils") {
+ deps = [
+ ":cr",
+ ]
+}
+
js_library("icon") {
deps = [
":cr",
@@ -49,7 +83,6 @@ js_library("i18n_template") {
js_library("i18n_behavior") {
deps = [
":load_time_data",
- ":parse_html_subset",
]
}
diff --git a/chromium/ui/webui/resources/js/cr/BUILD.gn b/chromium/ui/webui/resources/js/cr/BUILD.gn
new file mode 100644
index 00000000000..f78507863f2
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":event_target",
+ ":ui",
+ ]
+}
+
+js_library("event_target") {
+ deps = [
+ "..:cr",
+ ]
+}
+
+js_library("ui") {
+ deps = [
+ "..:cr",
+ ]
+}
diff --git a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
new file mode 100644
index 00000000000..70393b3b5d2
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
@@ -0,0 +1,250 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":alert_overlay",
+ ":array_data_model",
+ ":autocomplete_list",
+ ":command",
+ ":context_menu_button",
+ ":context_menu_handler",
+ ":dialogs",
+ ":drag_wrapper",
+ ":focus_grid",
+ ":focus_manager",
+ ":focus_outline_manager",
+ ":focus_row",
+ ":focus_without_ink",
+ ":grid",
+ ":list",
+ ":list_item",
+ ":list_selection_controller",
+ ":list_selection_model",
+ ":list_single_selection_model",
+ ":menu",
+ ":menu_button",
+ ":menu_item",
+ ":node_utils",
+ ":overlay",
+ ":position_util",
+ ":splitter",
+ ":table",
+ ":tree",
+ ]
+}
+
+js_library("alert_overlay") {
+ deps = [
+ "../..:cr",
+ "../..:util",
+ ]
+}
+
+js_library("array_data_model") {
+ deps = [
+ "..:event_target",
+ "../..:cr",
+ ]
+}
+
+js_library("autocomplete_list") {
+ deps = [
+ ":list",
+ ":list_single_selection_model",
+ ":position_util",
+ ]
+}
+
+js_library("command") {
+ deps = [
+ "..:ui",
+ "../..:cr",
+ ]
+}
+
+js_library("context_menu_button") {
+ deps = [
+ ":menu_button",
+ ]
+}
+
+js_library("context_menu_handler") {
+ deps = [
+ ":menu",
+ ":menu_button",
+ ":position_util",
+ "..:event_target",
+ "..:ui",
+ "../..:cr",
+ ]
+}
+
+js_library("dialogs") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("drag_wrapper") {
+ deps = [
+ "../..:assert",
+ "../..:cr",
+ ]
+}
+
+js_library("focus_grid") {
+ deps = [
+ ":focus_row",
+ "../..:assert",
+ "../..:cr",
+ "../..:event_tracker",
+ ]
+}
+
+js_library("focus_manager") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("focus_outline_manager") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("focus_row") {
+ deps = [
+ "../..:assert",
+ "../..:cr",
+ "../..:event_tracker",
+ "../..:util",
+ ]
+}
+
+js_library("focus_without_ink") {
+ deps = [
+ "..:ui",
+ "../..:cr",
+ ]
+}
+
+js_library("grid") {
+ deps = [
+ ":list",
+ ]
+}
+
+js_library("list") {
+ deps = [
+ ":array_data_model",
+ ":list_item",
+ ":list_selection_controller",
+ ":list_selection_model",
+ ]
+}
+
+js_library("list_item") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("list_selection_controller") {
+ deps = [
+ ":list_selection_model",
+ "../..:cr",
+ ]
+}
+
+js_library("list_selection_model") {
+ deps = [
+ "..:event_target",
+ "../..:cr",
+ ]
+}
+
+js_library("list_single_selection_model") {
+ deps = [
+ "..:event_target",
+ "../..:cr",
+ ]
+}
+
+js_library("menu_button") {
+ deps = [
+ ":menu",
+ ":menu_item",
+ ":position_util",
+ "..:ui",
+ "../..:assert",
+ "../..:cr",
+ "../..:event_tracker",
+ ]
+}
+
+js_library("menu_item") {
+ deps = [
+ ":command",
+ "..:ui",
+ "../..:cr",
+ "../..:load_time_data",
+ ]
+}
+
+js_library("menu") {
+ deps = [
+ ":menu_item",
+ "..:ui",
+ "../..:assert",
+ "../..:cr",
+ ]
+}
+
+js_library("node_utils") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("overlay") {
+ deps = [
+ "../..:cr",
+ "../..:util",
+ ]
+}
+
+js_library("position_util") {
+ deps = [
+ "../..:cr",
+ ]
+}
+
+js_library("splitter") {
+ deps = [
+ "..:ui",
+ "../..:cr",
+ ]
+}
+
+js_library("table") {
+ deps = [
+ ":list",
+ ":list_single_selection_model",
+ "table:table_column_model",
+ "table:table_header",
+ "table:table_list",
+ ]
+}
+
+js_library("tree") {
+ deps = [
+ "..:ui",
+ "../..:cr",
+ "../..:util",
+ ]
+}
diff --git a/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js b/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
index ccd9400608d..db05e102c36 100644
--- a/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/autocomplete_list.js
@@ -28,7 +28,7 @@ cr.define('cr.ui', function() {
*/
AutocompleteListItem.decorate = function(el) {
el.__proto__ = AutocompleteListItem.prototype;
- el.decorate();
+ /** @type {AutocompleteListItem} */ (el).decorate();
};
AutocompleteListItem.prototype = {
diff --git a/chromium/ui/webui/resources/js/cr/ui/grid.js b/chromium/ui/webui/resources/js/cr/ui/grid.js
index a71bf6b0e96..dc17e3c3f1c 100644
--- a/chromium/ui/webui/resources/js/cr/ui/grid.js
+++ b/chromium/ui/webui/resources/js/cr/ui/grid.js
@@ -245,7 +245,7 @@ cr.define('cr.ui', function() {
var firstIndex =
this.autoExpands ? 0 : this.getIndexForListOffset_(scrollTop);
var columns = this.columns;
- var count = this.autoExpands_ ?
+ var count = this.autoExpands ?
this.dataModel.length :
Math.max(
columns * (Math.ceil(clientHeight / itemHeight) + 1),
diff --git a/chromium/ui/webui/resources/js/cr/ui/list.js b/chromium/ui/webui/resources/js/cr/ui/list.js
index 3bb4ca554b4..6cf92762cf4 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list.js
@@ -7,6 +7,20 @@
// require: list_selection_controller.js
// require: list_item.js
+cr.exportPath('cr.ui');
+
+/**
+ * @typedef {{
+ * height: number,
+ * marginBottom: number,
+ * marginLeft: number,
+ * marginRight: number,
+ * marginTop: number,
+ * width: number
+ * }}
+ */
+cr.ui.Size;
+
/**
* @fileoverview This implements a list control.
*/
@@ -53,8 +67,7 @@ cr.define('cr.ui', function() {
* is needed. Note that lead item is allowed to have a different height, to
* accommodate lists where a single item at a time can be expanded to show
* more detail.
- * @type {?{height: number, marginTop: number, marginBottom: number,
- * width: number, marginLeft: number, marginRight: number}}
+ * @type {?cr.ui.Size}
* @private
*/
measured_: null,
@@ -347,7 +360,7 @@ cr.define('cr.ui', function() {
/**
* @return {number} The height of default item, measuring it if necessary.
- * @private
+ * @protected
*/
getDefaultItemHeight_: function() {
return this.getDefaultItemSize_().height;
@@ -375,9 +388,9 @@ cr.define('cr.ui', function() {
},
/**
- * @return {{height: number, width: number}} The height and width
- * of default item, measuring it if necessary.
- * @private
+ * @return {!cr.ui.Size} The height and width of default item, measuring it
+ * if necessary.
+ * @protected
*/
getDefaultItemSize_: function() {
if (!this.measured_ || !this.measured_.height) {
@@ -392,11 +405,8 @@ cr.define('cr.ui', function() {
* @param {cr.ui.ListItem=} opt_item The list item to use to do the
* measuring. If this is not provided an item will be created based on
* the first value in the model.
- * @return {{height: number, marginTop: number, marginBottom: number,
- * width: number, marginLeft: number, marginRight: number}}
- * The height and width of the item, taking
- * margins into account, and the top, bottom, left and right margins
- * themselves.
+ * @return {!cr.ui.Size} The height and width of the item, taking margins
+ * into account, and the top, bottom, left and right margins themselves.
*/
measureItem: function(opt_item) {
var dataModel = this.dataModel;
@@ -878,7 +888,7 @@ cr.define('cr.ui', function() {
* @param {number} offset The y offset in pixels to get the index of.
* @return {number} The index of the list item. Returns the list size if
* given offset exceeds the height of list.
- * @private
+ * @protected
*/
getIndexForListOffset_: function(offset) {
var itemHeight = this.getDefaultItemHeight_();
@@ -923,7 +933,7 @@ cr.define('cr.ui', function() {
* @param {number} startIndex The index of the first visible item.
* @param {number} endOffset The y offset in pixels of the end of the list.
* @return {number} The number of list items visible.
- * @private
+ * @protected
*/
countItemsInRange_: function(startIndex, endOffset) {
var endIndex = this.getIndexForListOffset_(endOffset);
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/table/BUILD.gn
new file mode 100644
index 00000000000..95a7d1685a3
--- /dev/null
+++ b/chromium/ui/webui/resources/js/cr/ui/table/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_library("table_column") {
+ deps = [
+ "../..:event_target",
+ "../../..:cr",
+ ]
+}
+
+js_library("table_column_model") {
+ deps = [
+ ":table_column",
+ "../../..:cr",
+ ]
+}
+
+js_library("table_header") {
+ deps = [
+ ":table_splitter",
+ "../../..:cr",
+ ]
+}
+
+js_library("table_list") {
+ deps = [
+ ":table_column_model",
+ "..:list",
+ "../../..:cr",
+ ]
+}
+
+js_library("table_splitter") {
+ deps = [
+ ":table_column_model",
+ "..:splitter",
+ "../../..:cr",
+ ]
+}
diff --git a/chromium/ui/webui/resources/js/cr/ui/table/table_header.js b/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
index 1422010a28a..602245d07a2 100644
--- a/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
+++ b/chromium/ui/webui/resources/js/cr/ui/table/table_header.js
@@ -201,7 +201,8 @@ cr.define('cr.ui.table', function() {
var minDistance = TableHeader.TOUCH_DRAG_AREA_WIDTH;
var candidate;
- var splitters = this.querySelectorAll('.table-header-splitter');
+ var splitters = /** @type {NodeList<cr.ui.TableSplitter>} */ (
+ this.querySelectorAll('.table-header-splitter'));
for (var i = 0; i < splitters.length; i++) {
var r = splitters[i].getBoundingClientRect();
if (clientX <= r.left && r.left - clientX <= minDistance) {
diff --git a/chromium/ui/webui/resources/polymer_resources.grdp b/chromium/ui/webui/resources/polymer_resources.grdp
index 6f4a7f9d3f0..46f529a4be2 100644
--- a/chromium/ui/webui/resources/polymer_resources.grdp
+++ b/chromium/ui/webui/resources/polymer_resources.grdp
@@ -784,22 +784,10 @@
file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_STYLES_ELEMENT_STYLES_PAPER_ITEM_STYLES_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/element-styles/paper-item-styles.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_PAPER_STYLES_ELEMENT_STYLES_PAPER_MATERIAL_STYLES_HTML"
file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/element-styles/paper-material-styles.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_STYLES_PAPER_STYLES_CLASSES_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/paper-styles-classes.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_STYLES_PAPER_STYLES_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/paper-styles.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_PAPER_STYLES_SHADOW_HTML"
file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/shadow.html"
type="chrome_html"
diff --git a/chromium/ui/webui/webui_features.gni b/chromium/ui/webui/webui_features.gni
new file mode 100644
index 00000000000..c20d7c39446
--- /dev/null
+++ b/chromium/ui/webui/webui_features.gni
@@ -0,0 +1,15 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+ # Optimize parts of Chrome's UI written with web technologies (HTML/CSS/JS)
+ # for runtime performance purposes. This does more work at compile time for
+ # speed benefits at runtime (so we skip in debug builds).
+ optimize_webui = !is_debug
+
+ # Enable closure type-checking for Chrome's web technology-based UI. This
+ # enables the webui_closure_compile target which does a no-op without this
+ # flag enabled. Requires Java.
+ closure_compile = is_chromeos || is_linux || is_android
+}
diff --git a/chromium/ui/wm/BUILD.gn b/chromium/ui/wm/BUILD.gn
index 7b832f66a3c..0b0e0f3bcd2 100644
--- a/chromium/ui/wm/BUILD.gn
+++ b/chromium/ui/wm/BUILD.gn
@@ -32,8 +32,6 @@ jumbo_component("wm") {
"core/focus_rules.h",
"core/native_cursor_manager.h",
"core/native_cursor_manager_delegate.h",
- "core/shadow.cc",
- "core/shadow.h",
"core/shadow_controller.cc",
"core/shadow_controller.h",
"core/shadow_types.cc",
@@ -71,6 +69,7 @@ jumbo_component("wm") {
"//ui/base",
"//ui/base/ime",
"//ui/compositor",
+ "//ui/compositor_extra",
"//ui/display",
"//ui/events",
"//ui/events:events_base",
@@ -129,7 +128,6 @@ test("wm_unittests") {
"core/easy_resize_window_targeter_unittest.cc",
"core/focus_controller_unittest.cc",
"core/shadow_controller_unittest.cc",
- "core/shadow_unittest.cc",
"core/transient_window_manager_unittest.cc",
"core/transient_window_stacking_client_unittest.cc",
"core/visibility_controller_unittest.cc",
@@ -143,13 +141,14 @@ test("wm_unittests") {
":wm",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//skia",
"//testing/gtest",
"//ui/aura:test_support",
"//ui/base:test_support",
"//ui/base/ime",
"//ui/compositor:test_support",
+ "//ui/compositor_extra",
"//ui/events:test_support",
"//ui/events/platform",
"//ui/gfx",
diff --git a/chromium/ui/wm/core/DEPS b/chromium/ui/wm/core/DEPS
index 73f5eb127aa..3d4d8af8767 100644
--- a/chromium/ui/wm/core/DEPS
+++ b/chromium/ui/wm/core/DEPS
@@ -11,6 +11,7 @@ include_rules = [
"+ui/base/ui_base_paths.h",
"+ui/base/ui_base_types.h",
"+ui/compositor",
+ "+ui/compositor_extra",
"+ui/events",
"+ui/gfx",
"+ui/resources/grit/ui_resources.h",
diff --git a/chromium/ui/wm/core/easy_resize_window_targeter_unittest.cc b/chromium/ui/wm/core/easy_resize_window_targeter_unittest.cc
index 092a17b5b68..a8cb4edf258 100644
--- a/chromium/ui/wm/core/easy_resize_window_targeter_unittest.cc
+++ b/chromium/ui/wm/core/easy_resize_window_targeter_unittest.cc
@@ -20,15 +20,6 @@ class TestEasyResizeWindowTargeter : public EasyResizeWindowTargeter {
public:
explicit TestEasyResizeWindowTargeter(aura::Window* window)
: EasyResizeWindowTargeter(window, gfx::Insets(), gfx::Insets()) {}
- ~TestEasyResizeWindowTargeter() override = default;
-
- void SetInsets(const gfx::Insets& mouse_extend,
- const gfx::Insets& touch_extend) {
- EasyResizeWindowTargeter::SetInsets(mouse_extend, touch_extend);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestEasyResizeWindowTargeter);
};
} // namespace
diff --git a/chromium/ui/wm/core/focus_controller_unittest.cc b/chromium/ui/wm/core/focus_controller_unittest.cc
index 2bab4acc933..684cdea9d3a 100644
--- a/chromium/ui/wm/core/focus_controller_unittest.cc
+++ b/chromium/ui/wm/core/focus_controller_unittest.cc
@@ -7,7 +7,6 @@
#include <map>
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/focus_change_observer.h"
@@ -954,7 +953,8 @@ class FocusControllerMouseEventTest : public FocusControllerDirectTestBase {
EXPECT_EQ(NULL, GetActiveWindow());
aura::Window* w1 = root_window()->GetChildById(1);
SimpleEventHandler handler;
- root_window()->PrependPreTargetHandler(&handler);
+ root_window()->AddPreTargetHandler(&handler,
+ ui::EventTarget::Priority::kSystem);
ui::test::EventGenerator generator(root_window(), w1);
generator.ClickLeftButton();
EXPECT_EQ(NULL, GetActiveWindow());
diff --git a/chromium/ui/wm/core/shadow_controller.cc b/chromium/ui/wm/core/shadow_controller.cc
index 875ed5e9b14..4e2033eb2e3 100644
--- a/chromium/ui/wm/core/shadow_controller.cc
+++ b/chromium/ui/wm/core/shadow_controller.cc
@@ -19,15 +19,15 @@
#include "ui/base/class_property.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer.h"
-#include "ui/wm/core/shadow.h"
+#include "ui/compositor_extra/shadow.h"
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
using std::make_pair;
-DEFINE_UI_CLASS_PROPERTY_TYPE(::wm::Shadow*);
-DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(::wm::Shadow, kShadowLayerKey, nullptr);
+DEFINE_UI_CLASS_PROPERTY_TYPE(ui::Shadow*);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ui::Shadow, kShadowLayerKey, nullptr);
namespace wm {
@@ -205,7 +205,7 @@ void ShadowController::Impl::OnWindowBoundsChanged(
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) {
- Shadow* shadow = GetShadowForWindow(window);
+ ui::Shadow* shadow = GetShadowForWindow(window);
if (shadow)
shadow->SetContentBounds(gfx::Rect(new_bounds.size()));
}
@@ -219,12 +219,12 @@ void ShadowController::Impl::OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
if (gained_active) {
- Shadow* shadow = GetShadowForWindow(gained_active);
+ ui::Shadow* shadow = GetShadowForWindow(gained_active);
if (shadow)
shadow->SetElevation(GetShadowElevationForActiveState(gained_active));
}
if (lost_active) {
- Shadow* shadow = GetShadowForWindow(lost_active);
+ ui::Shadow* shadow = GetShadowForWindow(lost_active);
if (shadow && GetShadowElevationConvertDefault(lost_active) ==
kShadowElevationInactiveWindow) {
shadow->SetElevation(
@@ -248,7 +248,7 @@ bool ShadowController::Impl::ShouldShowShadowForWindow(
void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
aura::Window* window) {
const bool should_show = ShouldShowShadowForWindow(window);
- Shadow* shadow = GetShadowForWindow(window);
+ ui::Shadow* shadow = GetShadowForWindow(window);
if (shadow) {
shadow->SetElevation(GetShadowElevationForActiveState(window));
shadow->layer()->SetVisible(should_show);
@@ -259,7 +259,7 @@ void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
DCHECK(!window->IsRootWindow());
- Shadow* shadow = new Shadow();
+ ui::Shadow* shadow = new ui::Shadow();
window->SetProperty(kShadowLayerKey, shadow);
int corner_radius = window->GetProperty(aura::client::kWindowCornerRadiusKey);
@@ -286,7 +286,7 @@ ShadowController::Impl::~Impl() {
// ShadowController ------------------------------------------------------------
-Shadow* ShadowController::GetShadowForWindow(aura::Window* window) {
+ui::Shadow* ShadowController::GetShadowForWindow(aura::Window* window) {
return window->GetProperty(kShadowLayerKey);
}
diff --git a/chromium/ui/wm/core/shadow_controller.h b/chromium/ui/wm/core/shadow_controller.h
index f9c3bee5336..5cdc329a0c2 100644
--- a/chromium/ui/wm/core/shadow_controller.h
+++ b/chromium/ui/wm/core/shadow_controller.h
@@ -17,10 +17,13 @@ namespace aura {
class Window;
}
+namespace ui {
+class Shadow;
+}
+
namespace wm {
class ActivationClient;
-class Shadow;
// ShadowController observes changes to windows and creates and updates drop
// shadows as needed. ShadowController itself is light weight and per
@@ -29,7 +32,7 @@ class Shadow;
class WM_CORE_EXPORT ShadowController : public ActivationChangeObserver {
public:
// Returns the shadow for the |window|, or NULL if no shadow exists.
- static Shadow* GetShadowForWindow(aura::Window* window);
+ static ui::Shadow* GetShadowForWindow(aura::Window* window);
explicit ShadowController(ActivationClient* activation_client);
~ShadowController() override;
diff --git a/chromium/ui/wm/core/shadow_controller_unittest.cc b/chromium/ui/wm/core/shadow_controller_unittest.cc
index c3af5692265..e9ad4d87c7b 100644
--- a/chromium/ui/wm/core/shadow_controller_unittest.cc
+++ b/chromium/ui/wm/core/shadow_controller_unittest.cc
@@ -15,8 +15,8 @@
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/compositor/layer.h"
+#include "ui/compositor_extra/shadow.h"
#include "ui/wm/core/default_activation_client.h"
-#include "ui/wm/core/shadow.h"
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
@@ -66,7 +66,7 @@ TEST_F(ShadowControllerTest, Shadow) {
EXPECT_FALSE(ShadowController::GetShadowForWindow(window.get()));
window->Show();
- const Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
+ const ui::Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
ASSERT_TRUE(shadow != NULL);
EXPECT_TRUE(shadow->layer()->visible());
@@ -99,7 +99,7 @@ TEST_F(ShadowControllerTest, ShadowBounds) {
// When the shadow is first created, it should use the window's size (but
// remain at the origin, since it's a child of the window's layer).
SetShadowElevation(window.get(), kShadowElevationInactiveWindow);
- const Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
+ const ui::Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
ASSERT_TRUE(shadow != NULL);
EXPECT_EQ(gfx::Rect(kOldBounds.size()).ToString(),
shadow->content_bounds().ToString());
@@ -122,7 +122,7 @@ TEST_F(ShadowControllerTest, ShadowStyle) {
ActivateWindow(window1.get());
// window1 is active, so style should have active appearance.
- Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get());
+ ui::Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get());
ASSERT_TRUE(shadow1 != NULL);
EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation());
@@ -136,7 +136,7 @@ TEST_F(ShadowControllerTest, ShadowStyle) {
ActivateWindow(window2.get());
// window1 is now inactive, so shadow should go inactive.
- Shadow* shadow2 = ShadowController::GetShadowForWindow(window2.get());
+ ui::Shadow* shadow2 = ShadowController::GetShadowForWindow(window2.get());
ASSERT_TRUE(shadow2 != NULL);
EXPECT_EQ(kShadowElevationInactiveWindow, shadow1->desired_elevation());
EXPECT_EQ(kShadowElevationActiveWindow, shadow2->desired_elevation());
@@ -150,7 +150,7 @@ TEST_F(ShadowControllerTest, ShowState) {
ParentWindow(window.get());
window->Show();
- Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
+ ui::Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
ASSERT_TRUE(shadow != NULL);
EXPECT_EQ(kShadowElevationInactiveWindow, shadow->desired_elevation());
@@ -173,7 +173,7 @@ TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) {
tooltip_window->SetBounds(gfx::Rect(10, 20, 300, 400));
tooltip_window->Show();
- Shadow* tooltip_shadow =
+ ui::Shadow* tooltip_shadow =
ShadowController::GetShadowForWindow(tooltip_window.get());
ASSERT_TRUE(tooltip_shadow != NULL);
EXPECT_EQ(kShadowElevationMenuOrTooltip, tooltip_shadow->desired_elevation());
@@ -185,7 +185,7 @@ TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) {
menu_window->SetBounds(gfx::Rect(10, 20, 300, 400));
menu_window->Show();
- Shadow* menu_shadow =
+ ui::Shadow* menu_shadow =
ShadowController::GetShadowForWindow(tooltip_window.get());
ASSERT_TRUE(menu_shadow != NULL);
EXPECT_EQ(kShadowElevationMenuOrTooltip, menu_shadow->desired_elevation());
@@ -203,7 +203,7 @@ TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) {
ActivateWindow(window1.get());
// window1 is active, so style should have active appearance.
- Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get());
+ ui::Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get());
ASSERT_TRUE(shadow1 != NULL);
EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation());
diff --git a/chromium/ui/wm/core/window_animations.cc b/chromium/ui/wm/core/window_animations.cc
index d8781f7afc0..af1a9b1368f 100644
--- a/chromium/ui/wm/core/window_animations.cc
+++ b/chromium/ui/wm/core/window_animations.cc
@@ -14,7 +14,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
diff --git a/chromium/ui/wm/core/window_util.cc b/chromium/ui/wm/core/window_util.cc
index d8cbfdc9e6a..7b00a00b95a 100644
--- a/chromium/ui/wm/core/window_util.cc
+++ b/chromium/ui/wm/core/window_util.cc
@@ -4,7 +4,6 @@
#include "ui/wm/core/window_util.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
diff --git a/chromium/ui/wm/core/wm_state.cc b/chromium/ui/wm/core/wm_state.cc
index a68006d0934..89410d8241f 100644
--- a/chromium/ui/wm/core/wm_state.cc
+++ b/chromium/ui/wm/core/wm_state.cc
@@ -4,7 +4,6 @@
#include "ui/wm/core/wm_state.h"
-#include "base/memory/ptr_util.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/wm/core/capture_controller.h"
#include "ui/wm/core/transient_window_controller.h"